xref: /optee_os/ta/pkcs11/src/pkcs11_token.c (revision e8dbd92c98f3ad1fddf5a18ccdf9c76a47cff3e8)
1c84ccd0aSEtienne Carriere // SPDX-License-Identifier: BSD-2-Clause
2c84ccd0aSEtienne Carriere /*
3c84ccd0aSEtienne Carriere  * Copyright (c) 2017-2020, Linaro Limited
4c84ccd0aSEtienne Carriere  */
5c84ccd0aSEtienne Carriere 
6c84ccd0aSEtienne Carriere #include <assert.h>
7d38f9635SEtienne Carriere #include <confine_array_index.h>
8c84ccd0aSEtienne Carriere #include <pkcs11_ta.h>
9c84ccd0aSEtienne Carriere #include <string.h>
10c84ccd0aSEtienne Carriere #include <string_ext.h>
11c84ccd0aSEtienne Carriere #include <sys/queue.h>
12c84ccd0aSEtienne Carriere #include <tee_api_types.h>
13c84ccd0aSEtienne Carriere #include <tee_internal_api_extensions.h>
14c84ccd0aSEtienne Carriere #include <util.h>
15c84ccd0aSEtienne Carriere 
16c84ccd0aSEtienne Carriere #include "pkcs11_helpers.h"
17ee49d9f2SEtienne Carriere #include "pkcs11_token.h"
1822ac6984SEtienne Carriere #include "serializer.h"
19c84ccd0aSEtienne Carriere 
20c84ccd0aSEtienne Carriere /* Provide 3 slots/tokens, ID is token index */
21c84ccd0aSEtienne Carriere #ifndef CFG_PKCS11_TA_TOKEN_COUNT
22c84ccd0aSEtienne Carriere #define TOKEN_COUNT		3
23c84ccd0aSEtienne Carriere #else
24c84ccd0aSEtienne Carriere #define TOKEN_COUNT		CFG_PKCS11_TA_TOKEN_COUNT
25c84ccd0aSEtienne Carriere #endif
26c84ccd0aSEtienne Carriere 
27e084583eSEtienne Carriere /*
28e084583eSEtienne Carriere  * Structure tracking client applications
29e084583eSEtienne Carriere  *
30e084583eSEtienne Carriere  * @link - chained list of registered client applications
31e084583eSEtienne Carriere  * @sessions - list of the PKCS11 sessions opened by the client application
32e084583eSEtienne Carriere  */
33e084583eSEtienne Carriere struct pkcs11_client {
34e084583eSEtienne Carriere 	TAILQ_ENTRY(pkcs11_client) link;
35e084583eSEtienne Carriere 	struct session_list session_list;
36e084583eSEtienne Carriere 	struct handle_db session_handle_db;
37e084583eSEtienne Carriere };
38e084583eSEtienne Carriere 
39c84ccd0aSEtienne Carriere /* Static allocation of tokens runtime instances (reset to 0 at load) */
40c84ccd0aSEtienne Carriere struct ck_token ck_token[TOKEN_COUNT];
41c84ccd0aSEtienne Carriere 
42e084583eSEtienne Carriere static struct client_list pkcs11_client_list =
43e084583eSEtienne Carriere 	TAILQ_HEAD_INITIALIZER(pkcs11_client_list);
44e084583eSEtienne Carriere 
456e4f8f17SEtienne Carriere static void close_ck_session(struct pkcs11_session *session);
466e4f8f17SEtienne Carriere 
47c84ccd0aSEtienne Carriere struct ck_token *get_token(unsigned int token_id)
48c84ccd0aSEtienne Carriere {
49d38f9635SEtienne Carriere 	if (token_id < TOKEN_COUNT)
50d38f9635SEtienne Carriere 		return &ck_token[confine_array_index(token_id, TOKEN_COUNT)];
51c84ccd0aSEtienne Carriere 
52d38f9635SEtienne Carriere 	return NULL;
53c84ccd0aSEtienne Carriere }
54c84ccd0aSEtienne Carriere 
55c84ccd0aSEtienne Carriere unsigned int get_token_id(struct ck_token *token)
56c84ccd0aSEtienne Carriere {
57c84ccd0aSEtienne Carriere 	ptrdiff_t id = token - ck_token;
58c84ccd0aSEtienne Carriere 
59c84ccd0aSEtienne Carriere 	assert(id >= 0 && id < TOKEN_COUNT);
60c84ccd0aSEtienne Carriere 	return id;
61c84ccd0aSEtienne Carriere }
62c84ccd0aSEtienne Carriere 
63e084583eSEtienne Carriere struct pkcs11_client *tee_session2client(void *tee_session)
64e084583eSEtienne Carriere {
65e084583eSEtienne Carriere 	struct pkcs11_client *client = NULL;
66e084583eSEtienne Carriere 
67e084583eSEtienne Carriere 	TAILQ_FOREACH(client, &pkcs11_client_list, link)
68e084583eSEtienne Carriere 		if (client == tee_session)
69e084583eSEtienne Carriere 			break;
70e084583eSEtienne Carriere 
71e084583eSEtienne Carriere 	return client;
72e084583eSEtienne Carriere }
73e084583eSEtienne Carriere 
746e4f8f17SEtienne Carriere struct pkcs11_session *pkcs11_handle2session(uint32_t handle,
756e4f8f17SEtienne Carriere 					     struct pkcs11_client *client)
766e4f8f17SEtienne Carriere {
776e4f8f17SEtienne Carriere 	return handle_lookup(&client->session_handle_db, handle);
786e4f8f17SEtienne Carriere }
796e4f8f17SEtienne Carriere 
80e084583eSEtienne Carriere struct pkcs11_client *register_client(void)
81e084583eSEtienne Carriere {
82e084583eSEtienne Carriere 	struct pkcs11_client *client = NULL;
83e084583eSEtienne Carriere 
84e084583eSEtienne Carriere 	client = TEE_Malloc(sizeof(*client), TEE_MALLOC_FILL_ZERO);
85e084583eSEtienne Carriere 	if (!client)
86e084583eSEtienne Carriere 		return NULL;
87e084583eSEtienne Carriere 
88e084583eSEtienne Carriere 	TAILQ_INSERT_HEAD(&pkcs11_client_list, client, link);
89e084583eSEtienne Carriere 	TAILQ_INIT(&client->session_list);
90e084583eSEtienne Carriere 	handle_db_init(&client->session_handle_db);
91e084583eSEtienne Carriere 
92e084583eSEtienne Carriere 	return client;
93e084583eSEtienne Carriere }
94e084583eSEtienne Carriere 
95e084583eSEtienne Carriere void unregister_client(struct pkcs11_client *client)
96e084583eSEtienne Carriere {
976e4f8f17SEtienne Carriere 	struct pkcs11_session *session = NULL;
986e4f8f17SEtienne Carriere 	struct pkcs11_session *next = NULL;
996e4f8f17SEtienne Carriere 
100e084583eSEtienne Carriere 	if (!client) {
101e084583eSEtienne Carriere 		EMSG("Invalid TEE session handle");
102e084583eSEtienne Carriere 		return;
103e084583eSEtienne Carriere 	}
104e084583eSEtienne Carriere 
1056e4f8f17SEtienne Carriere 	TAILQ_FOREACH_SAFE(session, &client->session_list, link, next)
1066e4f8f17SEtienne Carriere 		close_ck_session(session);
1076e4f8f17SEtienne Carriere 
108e084583eSEtienne Carriere 	TAILQ_REMOVE(&pkcs11_client_list, client, link);
109e084583eSEtienne Carriere 	handle_db_destroy(&client->session_handle_db);
110e084583eSEtienne Carriere 	TEE_Free(client);
111e084583eSEtienne Carriere }
112e084583eSEtienne Carriere 
113c84ccd0aSEtienne Carriere static TEE_Result pkcs11_token_init(unsigned int id)
114c84ccd0aSEtienne Carriere {
115c84ccd0aSEtienne Carriere 	struct ck_token *token = init_persistent_db(id);
116c84ccd0aSEtienne Carriere 
117c84ccd0aSEtienne Carriere 	if (!token)
118c84ccd0aSEtienne Carriere 		return TEE_ERROR_SECURITY;
119c84ccd0aSEtienne Carriere 
120c84ccd0aSEtienne Carriere 	if (token->state == PKCS11_TOKEN_RESET) {
121c84ccd0aSEtienne Carriere 		/* As per PKCS#11 spec, token resets to read/write state */
122c84ccd0aSEtienne Carriere 		token->state = PKCS11_TOKEN_READ_WRITE;
123c84ccd0aSEtienne Carriere 		token->session_count = 0;
124c84ccd0aSEtienne Carriere 		token->rw_session_count = 0;
125c84ccd0aSEtienne Carriere 	}
126c84ccd0aSEtienne Carriere 
127c84ccd0aSEtienne Carriere 	return TEE_SUCCESS;
128c84ccd0aSEtienne Carriere }
129c84ccd0aSEtienne Carriere 
130c84ccd0aSEtienne Carriere TEE_Result pkcs11_init(void)
131c84ccd0aSEtienne Carriere {
132c84ccd0aSEtienne Carriere 	unsigned int id = 0;
133c84ccd0aSEtienne Carriere 	TEE_Result ret = TEE_ERROR_GENERIC;
134c84ccd0aSEtienne Carriere 
135c84ccd0aSEtienne Carriere 	for (id = 0; id < TOKEN_COUNT; id++) {
136c84ccd0aSEtienne Carriere 		ret = pkcs11_token_init(id);
137c84ccd0aSEtienne Carriere 		if (ret)
138e084583eSEtienne Carriere 			break;
139c84ccd0aSEtienne Carriere 	}
140c84ccd0aSEtienne Carriere 
141c84ccd0aSEtienne Carriere 	return ret;
142c84ccd0aSEtienne Carriere }
143c84ccd0aSEtienne Carriere 
144c84ccd0aSEtienne Carriere void pkcs11_deinit(void)
145c84ccd0aSEtienne Carriere {
146c84ccd0aSEtienne Carriere 	unsigned int id = 0;
147c84ccd0aSEtienne Carriere 
148c84ccd0aSEtienne Carriere 	for (id = 0; id < TOKEN_COUNT; id++)
149c84ccd0aSEtienne Carriere 		close_persistent_db(get_token(id));
150c84ccd0aSEtienne Carriere }
15122ac6984SEtienne Carriere 
15222ac6984SEtienne Carriere uint32_t entry_ck_slot_list(uint32_t ptypes, TEE_Param *params)
15322ac6984SEtienne Carriere {
15422ac6984SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
15522ac6984SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
15622ac6984SEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
15722ac6984SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
15822ac6984SEtienne Carriere 	TEE_Param *out = &params[2];
15922ac6984SEtienne Carriere 	uint32_t token_id = 0;
16022ac6984SEtienne Carriere 	const size_t out_size = sizeof(token_id) * TOKEN_COUNT;
16122ac6984SEtienne Carriere 	uint8_t *id = NULL;
16222ac6984SEtienne Carriere 
16322ac6984SEtienne Carriere 	if (ptypes != exp_pt ||
16422ac6984SEtienne Carriere 	    params[0].memref.size != TEE_PARAM0_SIZE_MIN)
16522ac6984SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
16622ac6984SEtienne Carriere 
16722ac6984SEtienne Carriere 	if (out->memref.size < out_size) {
16822ac6984SEtienne Carriere 		out->memref.size = out_size;
16922ac6984SEtienne Carriere 
17022ac6984SEtienne Carriere 		if (out->memref.buffer)
17122ac6984SEtienne Carriere 			return PKCS11_CKR_BUFFER_TOO_SMALL;
17222ac6984SEtienne Carriere 		else
17322ac6984SEtienne Carriere 			return PKCS11_CKR_OK;
17422ac6984SEtienne Carriere 	}
17522ac6984SEtienne Carriere 
17622ac6984SEtienne Carriere 	for (token_id = 0, id = out->memref.buffer; token_id < TOKEN_COUNT;
17722ac6984SEtienne Carriere 	     token_id++, id += sizeof(token_id))
17822ac6984SEtienne Carriere 		TEE_MemMove(id, &token_id, sizeof(token_id));
17922ac6984SEtienne Carriere 
18022ac6984SEtienne Carriere 	out->memref.size = out_size;
18122ac6984SEtienne Carriere 
18222ac6984SEtienne Carriere 	return PKCS11_CKR_OK;
18322ac6984SEtienne Carriere }
184ce94efefSEtienne Carriere 
185b3ac5035SEtienne Carriere static void pad_str(uint8_t *str, size_t size)
186b3ac5035SEtienne Carriere {
187b3ac5035SEtienne Carriere 	int n = strnlen((char *)str, size);
188b3ac5035SEtienne Carriere 
189b3ac5035SEtienne Carriere 	TEE_MemFill(str + n, ' ', size - n);
190b3ac5035SEtienne Carriere }
191b3ac5035SEtienne Carriere 
192ce94efefSEtienne Carriere uint32_t entry_ck_slot_info(uint32_t ptypes, TEE_Param *params)
193ce94efefSEtienne Carriere {
194ce94efefSEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
195ce94efefSEtienne Carriere 						TEE_PARAM_TYPE_NONE,
196ce94efefSEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
197ce94efefSEtienne Carriere 						TEE_PARAM_TYPE_NONE);
198ce94efefSEtienne Carriere 	TEE_Param *ctrl = &params[0];
199ce94efefSEtienne Carriere 	TEE_Param *out = &params[2];
200ce94efefSEtienne Carriere 	uint32_t rv = 0;
201ce94efefSEtienne Carriere 	struct serialargs ctrlargs = { };
202ce94efefSEtienne Carriere 	uint32_t token_id = 0;
203ce94efefSEtienne Carriere 	struct ck_token *token = NULL;
204ce94efefSEtienne Carriere 	struct pkcs11_slot_info info = {
205ce94efefSEtienne Carriere 		.slot_description = PKCS11_SLOT_DESCRIPTION,
206ce94efefSEtienne Carriere 		.manufacturer_id = PKCS11_SLOT_MANUFACTURER,
207ce94efefSEtienne Carriere 		.flags = PKCS11_CKFS_TOKEN_PRESENT,
208ce94efefSEtienne Carriere 		.hardware_version = PKCS11_SLOT_HW_VERSION,
209ce94efefSEtienne Carriere 		.firmware_version = PKCS11_SLOT_FW_VERSION,
210ce94efefSEtienne Carriere 	};
211ce94efefSEtienne Carriere 
212ce94efefSEtienne Carriere 	COMPILE_TIME_ASSERT(sizeof(PKCS11_SLOT_DESCRIPTION) <=
213ce94efefSEtienne Carriere 			    sizeof(info.slot_description));
214ce94efefSEtienne Carriere 	COMPILE_TIME_ASSERT(sizeof(PKCS11_SLOT_MANUFACTURER) <=
215ce94efefSEtienne Carriere 			    sizeof(info.manufacturer_id));
216ce94efefSEtienne Carriere 
217ce94efefSEtienne Carriere 	if (ptypes != exp_pt || out->memref.size != sizeof(info))
218ce94efefSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
219ce94efefSEtienne Carriere 
220ce94efefSEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
221ce94efefSEtienne Carriere 
222ce94efefSEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(token_id));
223ce94efefSEtienne Carriere 	if (rv)
224ce94efefSEtienne Carriere 		return rv;
225ce94efefSEtienne Carriere 
226ce94efefSEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
227ce94efefSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
228ce94efefSEtienne Carriere 
229ce94efefSEtienne Carriere 	token = get_token(token_id);
230ce94efefSEtienne Carriere 	if (!token)
231ce94efefSEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
232ce94efefSEtienne Carriere 
233b3ac5035SEtienne Carriere 	pad_str(info.slot_description, sizeof(info.slot_description));
234b3ac5035SEtienne Carriere 	pad_str(info.manufacturer_id, sizeof(info.manufacturer_id));
235ce94efefSEtienne Carriere 
236ce94efefSEtienne Carriere 	out->memref.size = sizeof(info);
237ce94efefSEtienne Carriere 	TEE_MemMove(out->memref.buffer, &info, out->memref.size);
238ce94efefSEtienne Carriere 
239ce94efefSEtienne Carriere 	return PKCS11_CKR_OK;
240ce94efefSEtienne Carriere }
241030e7392SEtienne Carriere 
242030e7392SEtienne Carriere uint32_t entry_ck_token_info(uint32_t ptypes, TEE_Param *params)
243030e7392SEtienne Carriere {
244030e7392SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
245030e7392SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
246030e7392SEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
247030e7392SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
248030e7392SEtienne Carriere 	TEE_Param *ctrl = &params[0];
249030e7392SEtienne Carriere 	TEE_Param *out = &params[2];
250030e7392SEtienne Carriere 	uint32_t rv = 0;
251030e7392SEtienne Carriere 	struct serialargs ctrlargs = { };
252030e7392SEtienne Carriere 	uint32_t token_id = 0;
253030e7392SEtienne Carriere 	struct ck_token *token = NULL;
254030e7392SEtienne Carriere 	struct pkcs11_token_info info = {
255030e7392SEtienne Carriere 		.manufacturer_id = PKCS11_TOKEN_MANUFACTURER,
256030e7392SEtienne Carriere 		.model = PKCS11_TOKEN_MODEL,
257030e7392SEtienne Carriere 		.serial_number = PKCS11_TOKEN_SERIAL_NUMBER,
258030e7392SEtienne Carriere 		.max_session_count = UINT32_MAX,
259030e7392SEtienne Carriere 		.max_rw_session_count = UINT32_MAX,
260030e7392SEtienne Carriere 		.max_pin_len = PKCS11_TOKEN_PIN_SIZE_MAX,
261030e7392SEtienne Carriere 		.min_pin_len = PKCS11_TOKEN_PIN_SIZE_MIN,
262030e7392SEtienne Carriere 		.total_public_memory = UINT32_MAX,
263030e7392SEtienne Carriere 		.free_public_memory = UINT32_MAX,
264030e7392SEtienne Carriere 		.total_private_memory = UINT32_MAX,
265030e7392SEtienne Carriere 		.free_private_memory = UINT32_MAX,
266030e7392SEtienne Carriere 		.hardware_version = PKCS11_TOKEN_HW_VERSION,
267030e7392SEtienne Carriere 		.firmware_version = PKCS11_TOKEN_FW_VERSION,
268030e7392SEtienne Carriere 	};
269030e7392SEtienne Carriere 
270030e7392SEtienne Carriere 	if (ptypes != exp_pt || out->memref.size != sizeof(info))
271030e7392SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
272030e7392SEtienne Carriere 
273030e7392SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
274030e7392SEtienne Carriere 
275030e7392SEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(token_id));
276030e7392SEtienne Carriere 	if (rv)
277030e7392SEtienne Carriere 		return rv;
278030e7392SEtienne Carriere 
279030e7392SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
280030e7392SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
281030e7392SEtienne Carriere 
282030e7392SEtienne Carriere 	token = get_token(token_id);
283030e7392SEtienne Carriere 	if (!token)
284030e7392SEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
285030e7392SEtienne Carriere 
286030e7392SEtienne Carriere 	pad_str(info.manufacturer_id, sizeof(info.manufacturer_id));
287030e7392SEtienne Carriere 	pad_str(info.model, sizeof(info.model));
288030e7392SEtienne Carriere 	pad_str(info.serial_number, sizeof(info.serial_number));
289030e7392SEtienne Carriere 
290030e7392SEtienne Carriere 	TEE_MemMove(info.label, token->db_main->label, sizeof(info.label));
291030e7392SEtienne Carriere 
292030e7392SEtienne Carriere 	info.flags = token->db_main->flags;
293030e7392SEtienne Carriere 	info.session_count = token->session_count;
294030e7392SEtienne Carriere 	info.rw_session_count = token->rw_session_count;
295030e7392SEtienne Carriere 
296030e7392SEtienne Carriere 	TEE_MemMove(out->memref.buffer, &info, sizeof(info));
297030e7392SEtienne Carriere 
298030e7392SEtienne Carriere 	return PKCS11_CKR_OK;
299030e7392SEtienne Carriere }
3006f74919dSEtienne Carriere 
3016f74919dSEtienne Carriere static void dmsg_print_supported_mechanism(unsigned int token_id __maybe_unused,
3026f74919dSEtienne Carriere 					   uint32_t *array __maybe_unused,
3036f74919dSEtienne Carriere 					   size_t count __maybe_unused)
3046f74919dSEtienne Carriere {
3056f74919dSEtienne Carriere 	size_t __maybe_unused n = 0;
3066f74919dSEtienne Carriere 
3076f74919dSEtienne Carriere 	if (TRACE_LEVEL < TRACE_DEBUG)
3086f74919dSEtienne Carriere 		return;
3096f74919dSEtienne Carriere 
3106f74919dSEtienne Carriere 	for (n = 0; n < count; n++)
3116f74919dSEtienne Carriere 		DMSG("PKCS11 token %"PRIu32": mechanism 0x%04"PRIx32": %s",
3126f74919dSEtienne Carriere 		     token_id, array[n], id2str_mechanism(array[n]));
3136f74919dSEtienne Carriere }
3146f74919dSEtienne Carriere 
3156f74919dSEtienne Carriere uint32_t entry_ck_token_mecha_ids(uint32_t ptypes, TEE_Param *params)
3166f74919dSEtienne Carriere {
3176f74919dSEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
3186f74919dSEtienne Carriere 						TEE_PARAM_TYPE_NONE,
3196f74919dSEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
3206f74919dSEtienne Carriere 						TEE_PARAM_TYPE_NONE);
3216f74919dSEtienne Carriere 	TEE_Param *ctrl = &params[0];
3226f74919dSEtienne Carriere 	TEE_Param *out = &params[2];
3236f74919dSEtienne Carriere 	uint32_t rv = 0;
3246f74919dSEtienne Carriere 	struct serialargs ctrlargs = { };
3256f74919dSEtienne Carriere 	uint32_t token_id = 0;
3266f74919dSEtienne Carriere 	struct ck_token __maybe_unused *token = NULL;
3276f74919dSEtienne Carriere 	size_t count = 0;
3286f74919dSEtienne Carriere 	uint32_t *array = NULL;
3296f74919dSEtienne Carriere 
3306f74919dSEtienne Carriere 	if (ptypes != exp_pt)
3316f74919dSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
3326f74919dSEtienne Carriere 
3336f74919dSEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
3346f74919dSEtienne Carriere 
3356f74919dSEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(token_id));
3366f74919dSEtienne Carriere 	if (rv)
3376f74919dSEtienne Carriere 		return rv;
3386f74919dSEtienne Carriere 
3396f74919dSEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
3406f74919dSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
3416f74919dSEtienne Carriere 
3426f74919dSEtienne Carriere 	token = get_token(token_id);
3436f74919dSEtienne Carriere 	if (!token)
3446f74919dSEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
3456f74919dSEtienne Carriere 
3466f74919dSEtienne Carriere 	count = out->memref.size / sizeof(*array);
3476f74919dSEtienne Carriere 	array = tee_malloc_mechanism_list(&count);
3486f74919dSEtienne Carriere 
3496f74919dSEtienne Carriere 	if (out->memref.size < count * sizeof(*array)) {
3506f74919dSEtienne Carriere 		assert(!array);
3516f74919dSEtienne Carriere 		out->memref.size = count * sizeof(*array);
3526459f267SEtienne Carriere 		if (out->memref.buffer)
3536f74919dSEtienne Carriere 			return PKCS11_CKR_BUFFER_TOO_SMALL;
3546459f267SEtienne Carriere 		else
3556459f267SEtienne Carriere 			return PKCS11_CKR_OK;
3566f74919dSEtienne Carriere 	}
3576f74919dSEtienne Carriere 
3586f74919dSEtienne Carriere 	if (!array)
3596f74919dSEtienne Carriere 		return PKCS11_CKR_DEVICE_MEMORY;
3606f74919dSEtienne Carriere 
3616f74919dSEtienne Carriere 	dmsg_print_supported_mechanism(token_id, array, count);
3626f74919dSEtienne Carriere 
3636f74919dSEtienne Carriere 	out->memref.size = count * sizeof(*array);
3646f74919dSEtienne Carriere 	TEE_MemMove(out->memref.buffer, array, out->memref.size);
3656f74919dSEtienne Carriere 
3666f74919dSEtienne Carriere 	TEE_Free(array);
3676f74919dSEtienne Carriere 
3686f74919dSEtienne Carriere 	return rv;
3696f74919dSEtienne Carriere }
3701d3ebedbSEtienne Carriere 
3711d3ebedbSEtienne Carriere static void supported_mechanism_key_size(uint32_t proc_id,
3721d3ebedbSEtienne Carriere 					 uint32_t *max_key_size,
3731d3ebedbSEtienne Carriere 					 uint32_t *min_key_size)
3741d3ebedbSEtienne Carriere {
3751d3ebedbSEtienne Carriere 	switch (proc_id) {
3761d3ebedbSEtienne Carriere 	/* Will be filled once TA supports mechanisms */
3771d3ebedbSEtienne Carriere 	default:
3781d3ebedbSEtienne Carriere 		*min_key_size = 0;
3791d3ebedbSEtienne Carriere 		*max_key_size = 0;
3801d3ebedbSEtienne Carriere 		break;
3811d3ebedbSEtienne Carriere 	}
3821d3ebedbSEtienne Carriere }
3831d3ebedbSEtienne Carriere 
3841d3ebedbSEtienne Carriere uint32_t entry_ck_token_mecha_info(uint32_t ptypes, TEE_Param *params)
3851d3ebedbSEtienne Carriere {
3861d3ebedbSEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
3871d3ebedbSEtienne Carriere 						TEE_PARAM_TYPE_NONE,
3881d3ebedbSEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
3891d3ebedbSEtienne Carriere 						TEE_PARAM_TYPE_NONE);
3901d3ebedbSEtienne Carriere 	TEE_Param *ctrl = &params[0];
3911d3ebedbSEtienne Carriere 	TEE_Param *out = &params[2];
3921d3ebedbSEtienne Carriere 	uint32_t rv = 0;
3931d3ebedbSEtienne Carriere 	struct serialargs ctrlargs = { };
3941d3ebedbSEtienne Carriere 	uint32_t token_id = 0;
3951d3ebedbSEtienne Carriere 	uint32_t type = 0;
3961d3ebedbSEtienne Carriere 	struct ck_token *token = NULL;
3971d3ebedbSEtienne Carriere 	struct pkcs11_mechanism_info info = { };
3981d3ebedbSEtienne Carriere 
3991d3ebedbSEtienne Carriere 	if (ptypes != exp_pt || out->memref.size != sizeof(info))
4001d3ebedbSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
4011d3ebedbSEtienne Carriere 
4021d3ebedbSEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
4031d3ebedbSEtienne Carriere 
4041d3ebedbSEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(uint32_t));
4051d3ebedbSEtienne Carriere 	if (rv)
4061d3ebedbSEtienne Carriere 		return rv;
4071d3ebedbSEtienne Carriere 
4081d3ebedbSEtienne Carriere 	rv = serialargs_get(&ctrlargs, &type, sizeof(uint32_t));
4091d3ebedbSEtienne Carriere 	if (rv)
4101d3ebedbSEtienne Carriere 		return rv;
4111d3ebedbSEtienne Carriere 
4121d3ebedbSEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
4131d3ebedbSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
4141d3ebedbSEtienne Carriere 
4151d3ebedbSEtienne Carriere 	token = get_token(token_id);
4161d3ebedbSEtienne Carriere 	if (!token)
4171d3ebedbSEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
4181d3ebedbSEtienne Carriere 
4191d3ebedbSEtienne Carriere 	if (!mechanism_is_valid(type))
4201d3ebedbSEtienne Carriere 		return PKCS11_CKR_MECHANISM_INVALID;
4211d3ebedbSEtienne Carriere 
4221d3ebedbSEtienne Carriere 	info.flags = mechanism_supported_flags(type);
4231d3ebedbSEtienne Carriere 
4241d3ebedbSEtienne Carriere 	supported_mechanism_key_size(type, &info.min_key_size,
4251d3ebedbSEtienne Carriere 				     &info.max_key_size);
4261d3ebedbSEtienne Carriere 
4271d3ebedbSEtienne Carriere 	TEE_MemMove(out->memref.buffer, &info, sizeof(info));
4281d3ebedbSEtienne Carriere 
4291d3ebedbSEtienne Carriere 	DMSG("PKCS11 token %"PRIu32": mechanism 0x%"PRIx32" info",
4301d3ebedbSEtienne Carriere 	     token_id, type);
4311d3ebedbSEtienne Carriere 
4321d3ebedbSEtienne Carriere 	return PKCS11_CKR_OK;
4331d3ebedbSEtienne Carriere }
4346e4f8f17SEtienne Carriere 
4356e4f8f17SEtienne Carriere /* Select the ReadOnly or ReadWrite state for session login state */
4366e4f8f17SEtienne Carriere static void set_session_state(struct pkcs11_client *client,
4376e4f8f17SEtienne Carriere 			      struct pkcs11_session *session, bool readonly)
4386e4f8f17SEtienne Carriere {
4396e4f8f17SEtienne Carriere 	struct pkcs11_session *sess = NULL;
4406e4f8f17SEtienne Carriere 	enum pkcs11_session_state state = PKCS11_CKS_RO_PUBLIC_SESSION;
4416e4f8f17SEtienne Carriere 
4426e4f8f17SEtienne Carriere 	/* Default to public session if no session already registered */
4436e4f8f17SEtienne Carriere 	if (readonly)
4446e4f8f17SEtienne Carriere 		state = PKCS11_CKS_RO_PUBLIC_SESSION;
4456e4f8f17SEtienne Carriere 	else
4466e4f8f17SEtienne Carriere 		state = PKCS11_CKS_RW_PUBLIC_SESSION;
4476e4f8f17SEtienne Carriere 
4486e4f8f17SEtienne Carriere 	/*
4496e4f8f17SEtienne Carriere 	 * No need to check all client sessions, the first found in
4506e4f8f17SEtienne Carriere 	 * target token gives client login configuration.
4516e4f8f17SEtienne Carriere 	 */
4526e4f8f17SEtienne Carriere 	TAILQ_FOREACH(sess, &client->session_list, link) {
4536e4f8f17SEtienne Carriere 		assert(sess != session);
4546e4f8f17SEtienne Carriere 
4556e4f8f17SEtienne Carriere 		if (sess->token == session->token) {
4566e4f8f17SEtienne Carriere 			switch (sess->state) {
4576e4f8f17SEtienne Carriere 			case PKCS11_CKS_RW_PUBLIC_SESSION:
4586e4f8f17SEtienne Carriere 			case PKCS11_CKS_RO_PUBLIC_SESSION:
4596e4f8f17SEtienne Carriere 				if (readonly)
4606e4f8f17SEtienne Carriere 					state = PKCS11_CKS_RO_PUBLIC_SESSION;
4616e4f8f17SEtienne Carriere 				else
4626e4f8f17SEtienne Carriere 					state = PKCS11_CKS_RW_PUBLIC_SESSION;
4636e4f8f17SEtienne Carriere 				break;
4646e4f8f17SEtienne Carriere 			case PKCS11_CKS_RO_USER_FUNCTIONS:
4656e4f8f17SEtienne Carriere 			case PKCS11_CKS_RW_USER_FUNCTIONS:
4666e4f8f17SEtienne Carriere 				if (readonly)
4676e4f8f17SEtienne Carriere 					state = PKCS11_CKS_RO_USER_FUNCTIONS;
4686e4f8f17SEtienne Carriere 				else
4696e4f8f17SEtienne Carriere 					state = PKCS11_CKS_RW_USER_FUNCTIONS;
4706e4f8f17SEtienne Carriere 				break;
4716e4f8f17SEtienne Carriere 			case PKCS11_CKS_RW_SO_FUNCTIONS:
4726e4f8f17SEtienne Carriere 				if (readonly)
4736e4f8f17SEtienne Carriere 					TEE_Panic(0);
4746e4f8f17SEtienne Carriere 				else
4756e4f8f17SEtienne Carriere 					state = PKCS11_CKS_RW_SO_FUNCTIONS;
4766e4f8f17SEtienne Carriere 				break;
4776e4f8f17SEtienne Carriere 			default:
4786e4f8f17SEtienne Carriere 				TEE_Panic(0);
4796e4f8f17SEtienne Carriere 			}
4806e4f8f17SEtienne Carriere 			break;
4816e4f8f17SEtienne Carriere 		}
4826e4f8f17SEtienne Carriere 	}
4836e4f8f17SEtienne Carriere 
4846e4f8f17SEtienne Carriere 	session->state = state;
4856e4f8f17SEtienne Carriere }
4866e4f8f17SEtienne Carriere 
4876e4f8f17SEtienne Carriere uint32_t entry_ck_open_session(struct pkcs11_client *client,
4886e4f8f17SEtienne Carriere 			       uint32_t ptypes, TEE_Param *params)
4896e4f8f17SEtienne Carriere {
4906e4f8f17SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
4916e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
4926e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
4936e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
4946e4f8f17SEtienne Carriere 	TEE_Param *ctrl = &params[0];
4956e4f8f17SEtienne Carriere 	TEE_Param *out = &params[2];
4966e4f8f17SEtienne Carriere 	uint32_t rv = 0;
4976e4f8f17SEtienne Carriere 	struct serialargs ctrlargs = { };
4986e4f8f17SEtienne Carriere 	uint32_t token_id = 0;
4996e4f8f17SEtienne Carriere 	uint32_t flags = 0;
5006e4f8f17SEtienne Carriere 	struct ck_token *token = NULL;
5016e4f8f17SEtienne Carriere 	struct pkcs11_session *session = NULL;
5026e4f8f17SEtienne Carriere 	bool readonly = false;
5036e4f8f17SEtienne Carriere 
5046e4f8f17SEtienne Carriere 	if (!client || ptypes != exp_pt ||
5056e4f8f17SEtienne Carriere 	    out->memref.size != sizeof(session->handle))
5066e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
5076e4f8f17SEtienne Carriere 
5086e4f8f17SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
5096e4f8f17SEtienne Carriere 
5106e4f8f17SEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(token_id));
5116e4f8f17SEtienne Carriere 	if (rv)
5126e4f8f17SEtienne Carriere 		return rv;
5136e4f8f17SEtienne Carriere 
5146e4f8f17SEtienne Carriere 	rv = serialargs_get(&ctrlargs, &flags, sizeof(flags));
5156e4f8f17SEtienne Carriere 	if (rv)
5166e4f8f17SEtienne Carriere 		return rv;
5176e4f8f17SEtienne Carriere 
5186e4f8f17SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
5196e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
5206e4f8f17SEtienne Carriere 
5216e4f8f17SEtienne Carriere 	token = get_token(token_id);
5226e4f8f17SEtienne Carriere 	if (!token)
5236e4f8f17SEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
5246e4f8f17SEtienne Carriere 
5256e4f8f17SEtienne Carriere 	/* Sanitize session flags */
5266e4f8f17SEtienne Carriere 	if (!(flags & PKCS11_CKFSS_SERIAL_SESSION) ||
5276e4f8f17SEtienne Carriere 	    (flags & ~(PKCS11_CKFSS_RW_SESSION |
5286e4f8f17SEtienne Carriere 		       PKCS11_CKFSS_SERIAL_SESSION)))
5296e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
5306e4f8f17SEtienne Carriere 
5316e4f8f17SEtienne Carriere 	readonly = !(flags & PKCS11_CKFSS_RW_SESSION);
5326e4f8f17SEtienne Carriere 
5336e4f8f17SEtienne Carriere 	if (!readonly && token->state == PKCS11_TOKEN_READ_ONLY)
5346e4f8f17SEtienne Carriere 		return PKCS11_CKR_TOKEN_WRITE_PROTECTED;
5356e4f8f17SEtienne Carriere 
5366e4f8f17SEtienne Carriere 	if (readonly) {
5376e4f8f17SEtienne Carriere 		/* Specifically reject read-only session under SO login */
5386e4f8f17SEtienne Carriere 		TAILQ_FOREACH(session, &client->session_list, link)
5396e4f8f17SEtienne Carriere 			if (pkcs11_session_is_so(session))
5406e4f8f17SEtienne Carriere 				return PKCS11_CKR_SESSION_READ_WRITE_SO_EXISTS;
5416e4f8f17SEtienne Carriere 	}
5426e4f8f17SEtienne Carriere 
5436e4f8f17SEtienne Carriere 	session = TEE_Malloc(sizeof(*session), TEE_MALLOC_FILL_ZERO);
5446e4f8f17SEtienne Carriere 	if (!session)
5456e4f8f17SEtienne Carriere 		return PKCS11_CKR_DEVICE_MEMORY;
5466e4f8f17SEtienne Carriere 
5476e4f8f17SEtienne Carriere 	session->handle = handle_get(&client->session_handle_db, session);
5486e4f8f17SEtienne Carriere 	if (!session->handle) {
5496e4f8f17SEtienne Carriere 		TEE_Free(session);
5506e4f8f17SEtienne Carriere 		return PKCS11_CKR_DEVICE_MEMORY;
5516e4f8f17SEtienne Carriere 	}
5526e4f8f17SEtienne Carriere 
5536e4f8f17SEtienne Carriere 	session->token = token;
5546e4f8f17SEtienne Carriere 	session->client = client;
5556e4f8f17SEtienne Carriere 
5566e4f8f17SEtienne Carriere 	set_session_state(client, session, readonly);
5576e4f8f17SEtienne Carriere 
5586e4f8f17SEtienne Carriere 	TAILQ_INSERT_HEAD(&client->session_list, session, link);
5596e4f8f17SEtienne Carriere 
5606e4f8f17SEtienne Carriere 	session->token->session_count++;
5616e4f8f17SEtienne Carriere 	if (!readonly)
5626e4f8f17SEtienne Carriere 		session->token->rw_session_count++;
5636e4f8f17SEtienne Carriere 
5646e4f8f17SEtienne Carriere 	TEE_MemMove(out->memref.buffer, &session->handle,
5656e4f8f17SEtienne Carriere 		    sizeof(session->handle));
5666e4f8f17SEtienne Carriere 
5676e4f8f17SEtienne Carriere 	DMSG("Open PKCS11 session %"PRIu32, session->handle);
5686e4f8f17SEtienne Carriere 
5696e4f8f17SEtienne Carriere 	return PKCS11_CKR_OK;
5706e4f8f17SEtienne Carriere }
5716e4f8f17SEtienne Carriere 
5726e4f8f17SEtienne Carriere static void close_ck_session(struct pkcs11_session *session)
5736e4f8f17SEtienne Carriere {
5746e4f8f17SEtienne Carriere 	TAILQ_REMOVE(&session->client->session_list, session, link);
5756e4f8f17SEtienne Carriere 	handle_put(&session->client->session_handle_db, session->handle);
5766e4f8f17SEtienne Carriere 
5776e4f8f17SEtienne Carriere 	session->token->session_count--;
5786e4f8f17SEtienne Carriere 	if (pkcs11_session_is_read_write(session))
5796e4f8f17SEtienne Carriere 		session->token->rw_session_count--;
5806e4f8f17SEtienne Carriere 
5816e4f8f17SEtienne Carriere 	TEE_Free(session);
5826e4f8f17SEtienne Carriere 
5836e4f8f17SEtienne Carriere 	DMSG("Close PKCS11 session %"PRIu32, session->handle);
5846e4f8f17SEtienne Carriere }
5856e4f8f17SEtienne Carriere 
5866e4f8f17SEtienne Carriere uint32_t entry_ck_close_session(struct pkcs11_client *client,
5876e4f8f17SEtienne Carriere 				uint32_t ptypes, TEE_Param *params)
5886e4f8f17SEtienne Carriere {
5896e4f8f17SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
5906e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
5916e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
5926e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
5936e4f8f17SEtienne Carriere 	TEE_Param *ctrl = &params[0];
5946e4f8f17SEtienne Carriere 	uint32_t rv = 0;
5956e4f8f17SEtienne Carriere 	struct serialargs ctrlargs = { };
5966e4f8f17SEtienne Carriere 	uint32_t session_handle = 0;
5976e4f8f17SEtienne Carriere 	struct pkcs11_session *session = NULL;
5986e4f8f17SEtienne Carriere 
5996e4f8f17SEtienne Carriere 	if (!client || ptypes != exp_pt)
6006e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
6016e4f8f17SEtienne Carriere 
6026e4f8f17SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
6036e4f8f17SEtienne Carriere 
6046e4f8f17SEtienne Carriere 	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
6056e4f8f17SEtienne Carriere 	if (rv)
6066e4f8f17SEtienne Carriere 		return rv;
6076e4f8f17SEtienne Carriere 
6086e4f8f17SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
6096e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
6106e4f8f17SEtienne Carriere 
6116e4f8f17SEtienne Carriere 	session = pkcs11_handle2session(session_handle, client);
6126e4f8f17SEtienne Carriere 	if (!session)
6136e4f8f17SEtienne Carriere 		return PKCS11_CKR_SESSION_HANDLE_INVALID;
6146e4f8f17SEtienne Carriere 
6156e4f8f17SEtienne Carriere 	close_ck_session(session);
6166e4f8f17SEtienne Carriere 
6176e4f8f17SEtienne Carriere 	return PKCS11_CKR_OK;
6186e4f8f17SEtienne Carriere }
6196e4f8f17SEtienne Carriere 
6206e4f8f17SEtienne Carriere uint32_t entry_ck_close_all_sessions(struct pkcs11_client *client,
6216e4f8f17SEtienne Carriere 				     uint32_t ptypes, TEE_Param *params)
6226e4f8f17SEtienne Carriere {
6236e4f8f17SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
6246e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
6256e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
6266e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
6276e4f8f17SEtienne Carriere 	TEE_Param *ctrl = &params[0];
6286e4f8f17SEtienne Carriere 	uint32_t rv = 0;
6296e4f8f17SEtienne Carriere 	struct serialargs ctrlargs = { };
6306e4f8f17SEtienne Carriere 	uint32_t token_id = 0;
6316e4f8f17SEtienne Carriere 	struct ck_token *token = NULL;
6326e4f8f17SEtienne Carriere 	struct pkcs11_session *session = NULL;
6336e4f8f17SEtienne Carriere 	struct pkcs11_session *next = NULL;
6346e4f8f17SEtienne Carriere 
6356e4f8f17SEtienne Carriere 	if (!client || ptypes != exp_pt)
6366e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
6376e4f8f17SEtienne Carriere 
6386e4f8f17SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
6396e4f8f17SEtienne Carriere 
6406e4f8f17SEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(uint32_t));
6416e4f8f17SEtienne Carriere 	if (rv)
6426e4f8f17SEtienne Carriere 		return rv;
6436e4f8f17SEtienne Carriere 
6446e4f8f17SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
6456e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
6466e4f8f17SEtienne Carriere 
6476e4f8f17SEtienne Carriere 	token = get_token(token_id);
6486e4f8f17SEtienne Carriere 	if (!token)
6496e4f8f17SEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
6506e4f8f17SEtienne Carriere 
6516e4f8f17SEtienne Carriere 	DMSG("Close all sessions for PKCS11 token %"PRIu32, token_id);
6526e4f8f17SEtienne Carriere 
6536e4f8f17SEtienne Carriere 	TAILQ_FOREACH_SAFE(session, &client->session_list, link, next)
6546e4f8f17SEtienne Carriere 		if (session->token == token)
6556e4f8f17SEtienne Carriere 			close_ck_session(session);
6566e4f8f17SEtienne Carriere 
6576e4f8f17SEtienne Carriere 	return PKCS11_CKR_OK;
6586e4f8f17SEtienne Carriere }
6596e4f8f17SEtienne Carriere 
6606e4f8f17SEtienne Carriere uint32_t entry_ck_session_info(struct pkcs11_client *client,
6616e4f8f17SEtienne Carriere 			       uint32_t ptypes, TEE_Param *params)
6626e4f8f17SEtienne Carriere {
6636e4f8f17SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
6646e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
6656e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
6666e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
6676e4f8f17SEtienne Carriere 	TEE_Param *ctrl = &params[0];
6686e4f8f17SEtienne Carriere 	TEE_Param *out = &params[2];
6696e4f8f17SEtienne Carriere 	uint32_t rv = 0;
6706e4f8f17SEtienne Carriere 	struct serialargs ctrlargs = { };
6716e4f8f17SEtienne Carriere 	uint32_t session_handle = 0;
6726e4f8f17SEtienne Carriere 	struct pkcs11_session *session = NULL;
6736e4f8f17SEtienne Carriere 	struct pkcs11_session_info info = {
6746e4f8f17SEtienne Carriere 		.flags = PKCS11_CKFSS_SERIAL_SESSION,
6756e4f8f17SEtienne Carriere 	};
6766e4f8f17SEtienne Carriere 
6776e4f8f17SEtienne Carriere 	if (!client || ptypes != exp_pt || out->memref.size != sizeof(info))
6786e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
6796e4f8f17SEtienne Carriere 
6806e4f8f17SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
6816e4f8f17SEtienne Carriere 
6826e4f8f17SEtienne Carriere 	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
6836e4f8f17SEtienne Carriere 	if (rv)
6846e4f8f17SEtienne Carriere 		return rv;
6856e4f8f17SEtienne Carriere 
6866e4f8f17SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
6876e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
6886e4f8f17SEtienne Carriere 
6896e4f8f17SEtienne Carriere 	session = pkcs11_handle2session(session_handle, client);
6906e4f8f17SEtienne Carriere 	if (!session)
6916e4f8f17SEtienne Carriere 		return PKCS11_CKR_SESSION_HANDLE_INVALID;
6926e4f8f17SEtienne Carriere 
6936e4f8f17SEtienne Carriere 	info.slot_id = get_token_id(session->token);
6946e4f8f17SEtienne Carriere 	info.state = session->state;
6956e4f8f17SEtienne Carriere 	if (pkcs11_session_is_read_write(session))
6966e4f8f17SEtienne Carriere 		info.flags |= PKCS11_CKFSS_RW_SESSION;
6976e4f8f17SEtienne Carriere 
6986e4f8f17SEtienne Carriere 	TEE_MemMove(out->memref.buffer, &info, sizeof(info));
6996e4f8f17SEtienne Carriere 
7006e4f8f17SEtienne Carriere 	DMSG("Get find on PKCS11 session %"PRIu32, session->handle);
7016e4f8f17SEtienne Carriere 
7026e4f8f17SEtienne Carriere 	return PKCS11_CKR_OK;
7036e4f8f17SEtienne Carriere }
704f485be04SJens Wiklander 
705f485be04SJens Wiklander uint32_t entry_ck_token_initialize(uint32_t ptypes, TEE_Param *params)
706f485be04SJens Wiklander {
707f485be04SJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
708f485be04SJens Wiklander 						TEE_PARAM_TYPE_NONE,
709f485be04SJens Wiklander 						TEE_PARAM_TYPE_NONE,
710f485be04SJens Wiklander 						TEE_PARAM_TYPE_NONE);
711f485be04SJens Wiklander 	char label[PKCS11_TOKEN_LABEL_SIZE] = { 0 };
712f485be04SJens Wiklander 	struct pkcs11_client *client = NULL;
713f485be04SJens Wiklander 	struct pkcs11_session *sess = NULL;
714f485be04SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
715f485be04SJens Wiklander 	struct serialargs ctrlargs = { };
716f485be04SJens Wiklander 	struct ck_token *token = NULL;
717f485be04SJens Wiklander 	TEE_Param *ctrl = params;
718f485be04SJens Wiklander 	uint32_t token_id = 0;
719f485be04SJens Wiklander 	uint32_t pin_size = 0;
720f485be04SJens Wiklander 	void *pin = NULL;
721f485be04SJens Wiklander 
722f485be04SJens Wiklander 	if (ptypes != exp_pt)
723f485be04SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
724f485be04SJens Wiklander 
725f485be04SJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
726f485be04SJens Wiklander 
727f485be04SJens Wiklander 	rc = serialargs_get(&ctrlargs, &token_id, sizeof(uint32_t));
728f485be04SJens Wiklander 	if (rc)
729f485be04SJens Wiklander 		return rc;
730f485be04SJens Wiklander 
731f485be04SJens Wiklander 	rc = serialargs_get(&ctrlargs, &pin_size, sizeof(uint32_t));
732f485be04SJens Wiklander 	if (rc)
733f485be04SJens Wiklander 		return rc;
734f485be04SJens Wiklander 
735f485be04SJens Wiklander 	rc = serialargs_get(&ctrlargs, &label, PKCS11_TOKEN_LABEL_SIZE);
736f485be04SJens Wiklander 	if (rc)
737f485be04SJens Wiklander 		return rc;
738f485be04SJens Wiklander 
739f485be04SJens Wiklander 	rc = serialargs_get_ptr(&ctrlargs, &pin, pin_size);
740f485be04SJens Wiklander 	if (rc)
741f485be04SJens Wiklander 		return rc;
742f485be04SJens Wiklander 
743f485be04SJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs))
744f485be04SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
745f485be04SJens Wiklander 
746f485be04SJens Wiklander 	token = get_token(token_id);
747f485be04SJens Wiklander 	if (!token)
748f485be04SJens Wiklander 		return PKCS11_CKR_SLOT_ID_INVALID;
749f485be04SJens Wiklander 
750f485be04SJens Wiklander 	if (token->db_main->flags & PKCS11_CKFT_SO_PIN_LOCKED) {
751f485be04SJens Wiklander 		IMSG("Token %"PRIu32": SO PIN locked", token_id);
752f485be04SJens Wiklander 		return PKCS11_CKR_PIN_LOCKED;
753f485be04SJens Wiklander 	}
754f485be04SJens Wiklander 
755f485be04SJens Wiklander 	/* Check there's no open session on this token */
756f485be04SJens Wiklander 	TAILQ_FOREACH(client, &pkcs11_client_list, link)
757f485be04SJens Wiklander 		TAILQ_FOREACH(sess, &client->session_list, link)
758f485be04SJens Wiklander 			if (sess->token == token)
759f485be04SJens Wiklander 				return PKCS11_CKR_SESSION_EXISTS;
760f485be04SJens Wiklander 
761f485be04SJens Wiklander 	if (!token->db_main->so_pin_salt) {
762f485be04SJens Wiklander 		/*
763f485be04SJens Wiklander 		 * The spec doesn't permit returning
764f485be04SJens Wiklander 		 * PKCS11_CKR_PIN_LEN_RANGE for this function, take another
765f485be04SJens Wiklander 		 * error code.
766f485be04SJens Wiklander 		 */
767f485be04SJens Wiklander 		if (pin_size < PKCS11_TOKEN_PIN_SIZE_MIN ||
768f485be04SJens Wiklander 		    pin_size > PKCS11_TOKEN_PIN_SIZE_MAX)
769f485be04SJens Wiklander 			return PKCS11_CKR_ARGUMENTS_BAD;
770f485be04SJens Wiklander 
771f485be04SJens Wiklander 		rc = hash_pin(PKCS11_CKU_SO, pin, pin_size,
772f485be04SJens Wiklander 			      &token->db_main->so_pin_salt,
773f485be04SJens Wiklander 			      token->db_main->so_pin_hash);
774f485be04SJens Wiklander 		if (rc)
775f485be04SJens Wiklander 			return rc;
776f485be04SJens Wiklander 
777f485be04SJens Wiklander 		update_persistent_db(token);
778f485be04SJens Wiklander 
779f485be04SJens Wiklander 		goto inited;
780f485be04SJens Wiklander 	}
781f485be04SJens Wiklander 
782f485be04SJens Wiklander 	rc = verify_pin(PKCS11_CKU_SO, pin, pin_size,
783f485be04SJens Wiklander 			token->db_main->so_pin_salt,
784f485be04SJens Wiklander 			token->db_main->so_pin_hash);
785f485be04SJens Wiklander 	if (rc) {
786f485be04SJens Wiklander 		unsigned int pin_count = 0;
787f485be04SJens Wiklander 
788f485be04SJens Wiklander 		if (rc != PKCS11_CKR_PIN_INCORRECT)
789f485be04SJens Wiklander 			return rc;
790f485be04SJens Wiklander 
791f485be04SJens Wiklander 		token->db_main->flags |= PKCS11_CKFT_SO_PIN_COUNT_LOW;
792f485be04SJens Wiklander 		token->db_main->so_pin_count++;
793f485be04SJens Wiklander 
794f485be04SJens Wiklander 		pin_count = token->db_main->so_pin_count;
795f485be04SJens Wiklander 		if (pin_count == PKCS11_TOKEN_SO_PIN_COUNT_MAX - 1)
796f485be04SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_SO_PIN_FINAL_TRY;
797f485be04SJens Wiklander 		if (pin_count == PKCS11_TOKEN_SO_PIN_COUNT_MAX)
798f485be04SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_SO_PIN_LOCKED;
799f485be04SJens Wiklander 
800f485be04SJens Wiklander 		update_persistent_db(token);
801f485be04SJens Wiklander 
802f485be04SJens Wiklander 		return PKCS11_CKR_PIN_INCORRECT;
803f485be04SJens Wiklander 	}
804f485be04SJens Wiklander 
805f485be04SJens Wiklander 	token->db_main->flags &= ~(PKCS11_CKFT_SO_PIN_COUNT_LOW |
806f485be04SJens Wiklander 				   PKCS11_CKFT_SO_PIN_FINAL_TRY);
807f485be04SJens Wiklander 	token->db_main->so_pin_count = 0;
808f485be04SJens Wiklander 
809f485be04SJens Wiklander inited:
810f485be04SJens Wiklander 	TEE_MemMove(token->db_main->label, label, PKCS11_TOKEN_LABEL_SIZE);
811f485be04SJens Wiklander 	token->db_main->flags |= PKCS11_CKFT_TOKEN_INITIALIZED;
812f485be04SJens Wiklander 	/* Reset user PIN */
813f485be04SJens Wiklander 	token->db_main->user_pin_salt = 0;
814f485be04SJens Wiklander 	token->db_main->flags &= ~(PKCS11_CKFT_USER_PIN_INITIALIZED |
815f485be04SJens Wiklander 				   PKCS11_CKFT_USER_PIN_COUNT_LOW |
816f485be04SJens Wiklander 				   PKCS11_CKFT_USER_PIN_FINAL_TRY |
817f485be04SJens Wiklander 				   PKCS11_CKFT_USER_PIN_LOCKED |
818f485be04SJens Wiklander 				   PKCS11_CKFT_USER_PIN_TO_BE_CHANGED);
819f485be04SJens Wiklander 
820f485be04SJens Wiklander 	update_persistent_db(token);
821f485be04SJens Wiklander 
822f485be04SJens Wiklander 	IMSG("PKCS11 token %"PRIu32": initialized", token_id);
823f485be04SJens Wiklander 
824f485be04SJens Wiklander 	return PKCS11_CKR_OK;
825f485be04SJens Wiklander }
826*e8dbd92cSJens Wiklander 
827*e8dbd92cSJens Wiklander static enum pkcs11_rc set_pin(struct pkcs11_session *session,
828*e8dbd92cSJens Wiklander 			      uint8_t *new_pin, size_t new_pin_size,
829*e8dbd92cSJens Wiklander 			      enum pkcs11_user_type user_type)
830*e8dbd92cSJens Wiklander {
831*e8dbd92cSJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
832*e8dbd92cSJens Wiklander 	uint32_t flags_clear = 0;
833*e8dbd92cSJens Wiklander 	uint32_t flags_set = 0;
834*e8dbd92cSJens Wiklander 
835*e8dbd92cSJens Wiklander 	if (session->token->db_main->flags & PKCS11_CKFT_WRITE_PROTECTED)
836*e8dbd92cSJens Wiklander 		return PKCS11_CKR_TOKEN_WRITE_PROTECTED;
837*e8dbd92cSJens Wiklander 
838*e8dbd92cSJens Wiklander 	if (!pkcs11_session_is_read_write(session))
839*e8dbd92cSJens Wiklander 		return PKCS11_CKR_SESSION_READ_ONLY;
840*e8dbd92cSJens Wiklander 
841*e8dbd92cSJens Wiklander 	if (new_pin_size < PKCS11_TOKEN_PIN_SIZE_MIN ||
842*e8dbd92cSJens Wiklander 	    new_pin_size > PKCS11_TOKEN_PIN_SIZE_MAX)
843*e8dbd92cSJens Wiklander 		return PKCS11_CKR_PIN_LEN_RANGE;
844*e8dbd92cSJens Wiklander 
845*e8dbd92cSJens Wiklander 	switch (user_type) {
846*e8dbd92cSJens Wiklander 	case PKCS11_CKU_SO:
847*e8dbd92cSJens Wiklander 		rc = hash_pin(user_type, new_pin, new_pin_size,
848*e8dbd92cSJens Wiklander 			      &session->token->db_main->so_pin_salt,
849*e8dbd92cSJens Wiklander 			      session->token->db_main->so_pin_hash);
850*e8dbd92cSJens Wiklander 		if (rc)
851*e8dbd92cSJens Wiklander 			return rc;
852*e8dbd92cSJens Wiklander 		session->token->db_main->so_pin_count = 0;
853*e8dbd92cSJens Wiklander 		flags_clear = PKCS11_CKFT_SO_PIN_COUNT_LOW |
854*e8dbd92cSJens Wiklander 			      PKCS11_CKFT_SO_PIN_FINAL_TRY |
855*e8dbd92cSJens Wiklander 			      PKCS11_CKFT_SO_PIN_LOCKED |
856*e8dbd92cSJens Wiklander 			      PKCS11_CKFT_SO_PIN_TO_BE_CHANGED;
857*e8dbd92cSJens Wiklander 		break;
858*e8dbd92cSJens Wiklander 	case PKCS11_CKU_USER:
859*e8dbd92cSJens Wiklander 		rc = hash_pin(user_type, new_pin, new_pin_size,
860*e8dbd92cSJens Wiklander 			      &session->token->db_main->user_pin_salt,
861*e8dbd92cSJens Wiklander 			      session->token->db_main->user_pin_hash);
862*e8dbd92cSJens Wiklander 		if (rc)
863*e8dbd92cSJens Wiklander 			return rc;
864*e8dbd92cSJens Wiklander 		session->token->db_main->user_pin_count = 0;
865*e8dbd92cSJens Wiklander 		flags_clear = PKCS11_CKFT_USER_PIN_COUNT_LOW |
866*e8dbd92cSJens Wiklander 			      PKCS11_CKFT_USER_PIN_FINAL_TRY |
867*e8dbd92cSJens Wiklander 			      PKCS11_CKFT_USER_PIN_LOCKED |
868*e8dbd92cSJens Wiklander 			      PKCS11_CKFT_USER_PIN_TO_BE_CHANGED;
869*e8dbd92cSJens Wiklander 		flags_set = PKCS11_CKFT_USER_PIN_INITIALIZED;
870*e8dbd92cSJens Wiklander 		break;
871*e8dbd92cSJens Wiklander 	default:
872*e8dbd92cSJens Wiklander 		return PKCS11_CKR_FUNCTION_FAILED;
873*e8dbd92cSJens Wiklander 	}
874*e8dbd92cSJens Wiklander 
875*e8dbd92cSJens Wiklander 	session->token->db_main->flags &= ~flags_clear;
876*e8dbd92cSJens Wiklander 	session->token->db_main->flags |= flags_set;
877*e8dbd92cSJens Wiklander 
878*e8dbd92cSJens Wiklander 	update_persistent_db(session->token);
879*e8dbd92cSJens Wiklander 
880*e8dbd92cSJens Wiklander 	return PKCS11_CKR_OK;
881*e8dbd92cSJens Wiklander }
882*e8dbd92cSJens Wiklander 
883*e8dbd92cSJens Wiklander uint32_t entry_ck_init_pin(struct pkcs11_client *client,
884*e8dbd92cSJens Wiklander 			   uint32_t ptypes, TEE_Param *params)
885*e8dbd92cSJens Wiklander {
886*e8dbd92cSJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
887*e8dbd92cSJens Wiklander 						TEE_PARAM_TYPE_NONE,
888*e8dbd92cSJens Wiklander 						TEE_PARAM_TYPE_NONE,
889*e8dbd92cSJens Wiklander 						TEE_PARAM_TYPE_NONE);
890*e8dbd92cSJens Wiklander 	struct pkcs11_session *session = NULL;
891*e8dbd92cSJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
892*e8dbd92cSJens Wiklander 	struct serialargs ctrlargs = { };
893*e8dbd92cSJens Wiklander 	uint32_t session_handle = 0;
894*e8dbd92cSJens Wiklander 	TEE_Param *ctrl = params;
895*e8dbd92cSJens Wiklander 	uint32_t pin_size = 0;
896*e8dbd92cSJens Wiklander 	void *pin = NULL;
897*e8dbd92cSJens Wiklander 
898*e8dbd92cSJens Wiklander 	if (!client || ptypes != exp_pt)
899*e8dbd92cSJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
900*e8dbd92cSJens Wiklander 
901*e8dbd92cSJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
902*e8dbd92cSJens Wiklander 
903*e8dbd92cSJens Wiklander 	rc = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
904*e8dbd92cSJens Wiklander 	if (rc)
905*e8dbd92cSJens Wiklander 		return rc;
906*e8dbd92cSJens Wiklander 
907*e8dbd92cSJens Wiklander 	rc = serialargs_get(&ctrlargs, &pin_size, sizeof(uint32_t));
908*e8dbd92cSJens Wiklander 	if (rc)
909*e8dbd92cSJens Wiklander 		return rc;
910*e8dbd92cSJens Wiklander 
911*e8dbd92cSJens Wiklander 	rc = serialargs_get_ptr(&ctrlargs, &pin, pin_size);
912*e8dbd92cSJens Wiklander 	if (rc)
913*e8dbd92cSJens Wiklander 		return rc;
914*e8dbd92cSJens Wiklander 
915*e8dbd92cSJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs))
916*e8dbd92cSJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
917*e8dbd92cSJens Wiklander 
918*e8dbd92cSJens Wiklander 	session = pkcs11_handle2session(session_handle, client);
919*e8dbd92cSJens Wiklander 	if (!session)
920*e8dbd92cSJens Wiklander 		return PKCS11_CKR_SESSION_HANDLE_INVALID;
921*e8dbd92cSJens Wiklander 
922*e8dbd92cSJens Wiklander 	if (!pkcs11_session_is_so(session))
923*e8dbd92cSJens Wiklander 		return PKCS11_CKR_USER_NOT_LOGGED_IN;
924*e8dbd92cSJens Wiklander 
925*e8dbd92cSJens Wiklander 	assert(session->token->db_main->flags & PKCS11_CKFT_TOKEN_INITIALIZED);
926*e8dbd92cSJens Wiklander 
927*e8dbd92cSJens Wiklander 	IMSG("PKCS11 session %"PRIu32": init PIN", session_handle);
928*e8dbd92cSJens Wiklander 
929*e8dbd92cSJens Wiklander 	return set_pin(session, pin, pin_size, PKCS11_CKU_USER);
930*e8dbd92cSJens Wiklander }
931