xref: /optee_os/ta/pkcs11/src/pkcs11_token.c (revision 12253e9e5fdcb3d9e5321fc688dba65c56ef1ed7)
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 
17512cbf1dSJens Wiklander #include "attributes.h"
1849443fc0SEtienne Carriere #include "handle.h"
19c84ccd0aSEtienne Carriere #include "pkcs11_helpers.h"
20ee49d9f2SEtienne Carriere #include "pkcs11_token.h"
2155e6965cSEtienne Carriere #include "processing.h"
2222ac6984SEtienne Carriere #include "serializer.h"
2349443fc0SEtienne Carriere #include "token_capabilities.h"
24c84ccd0aSEtienne Carriere 
25c84ccd0aSEtienne Carriere /* Provide 3 slots/tokens, ID is token index */
26c84ccd0aSEtienne Carriere #ifndef CFG_PKCS11_TA_TOKEN_COUNT
27c84ccd0aSEtienne Carriere #define TOKEN_COUNT		3
28c84ccd0aSEtienne Carriere #else
29c84ccd0aSEtienne Carriere #define TOKEN_COUNT		CFG_PKCS11_TA_TOKEN_COUNT
30c84ccd0aSEtienne Carriere #endif
31c84ccd0aSEtienne Carriere 
32e084583eSEtienne Carriere /*
33e084583eSEtienne Carriere  * Structure tracking client applications
34e084583eSEtienne Carriere  *
35e084583eSEtienne Carriere  * @link - chained list of registered client applications
36e084583eSEtienne Carriere  * @sessions - list of the PKCS11 sessions opened by the client application
37e084583eSEtienne Carriere  */
38e084583eSEtienne Carriere struct pkcs11_client {
39e084583eSEtienne Carriere 	TAILQ_ENTRY(pkcs11_client) link;
40e084583eSEtienne Carriere 	struct session_list session_list;
41e084583eSEtienne Carriere 	struct handle_db session_handle_db;
42e084583eSEtienne Carriere };
43e084583eSEtienne Carriere 
44c84ccd0aSEtienne Carriere /* Static allocation of tokens runtime instances (reset to 0 at load) */
45c84ccd0aSEtienne Carriere struct ck_token ck_token[TOKEN_COUNT];
46c84ccd0aSEtienne Carriere 
47e084583eSEtienne Carriere static struct client_list pkcs11_client_list =
48e084583eSEtienne Carriere 	TAILQ_HEAD_INITIALIZER(pkcs11_client_list);
49e084583eSEtienne Carriere 
506e4f8f17SEtienne Carriere static void close_ck_session(struct pkcs11_session *session);
516e4f8f17SEtienne Carriere 
52c84ccd0aSEtienne Carriere struct ck_token *get_token(unsigned int token_id)
53c84ccd0aSEtienne Carriere {
54d38f9635SEtienne Carriere 	if (token_id < TOKEN_COUNT)
55d38f9635SEtienne Carriere 		return &ck_token[confine_array_index(token_id, TOKEN_COUNT)];
56c84ccd0aSEtienne Carriere 
57d38f9635SEtienne Carriere 	return NULL;
58c84ccd0aSEtienne Carriere }
59c84ccd0aSEtienne Carriere 
60c84ccd0aSEtienne Carriere unsigned int get_token_id(struct ck_token *token)
61c84ccd0aSEtienne Carriere {
62c84ccd0aSEtienne Carriere 	ptrdiff_t id = token - ck_token;
63c84ccd0aSEtienne Carriere 
64c84ccd0aSEtienne Carriere 	assert(id >= 0 && id < TOKEN_COUNT);
65c84ccd0aSEtienne Carriere 	return id;
66c84ccd0aSEtienne Carriere }
67c84ccd0aSEtienne Carriere 
68e084583eSEtienne Carriere struct pkcs11_client *tee_session2client(void *tee_session)
69e084583eSEtienne Carriere {
70e084583eSEtienne Carriere 	struct pkcs11_client *client = NULL;
71e084583eSEtienne Carriere 
72e084583eSEtienne Carriere 	TAILQ_FOREACH(client, &pkcs11_client_list, link)
73e084583eSEtienne Carriere 		if (client == tee_session)
74e084583eSEtienne Carriere 			break;
75e084583eSEtienne Carriere 
76e084583eSEtienne Carriere 	return client;
77e084583eSEtienne Carriere }
78e084583eSEtienne Carriere 
796e4f8f17SEtienne Carriere struct pkcs11_session *pkcs11_handle2session(uint32_t handle,
806e4f8f17SEtienne Carriere 					     struct pkcs11_client *client)
816e4f8f17SEtienne Carriere {
826e4f8f17SEtienne Carriere 	return handle_lookup(&client->session_handle_db, handle);
836e4f8f17SEtienne Carriere }
846e4f8f17SEtienne Carriere 
85e084583eSEtienne Carriere struct pkcs11_client *register_client(void)
86e084583eSEtienne Carriere {
87e084583eSEtienne Carriere 	struct pkcs11_client *client = NULL;
88e084583eSEtienne Carriere 
89e084583eSEtienne Carriere 	client = TEE_Malloc(sizeof(*client), TEE_MALLOC_FILL_ZERO);
90e084583eSEtienne Carriere 	if (!client)
91e084583eSEtienne Carriere 		return NULL;
92e084583eSEtienne Carriere 
93e084583eSEtienne Carriere 	TAILQ_INSERT_HEAD(&pkcs11_client_list, client, link);
94e084583eSEtienne Carriere 	TAILQ_INIT(&client->session_list);
95e084583eSEtienne Carriere 	handle_db_init(&client->session_handle_db);
96e084583eSEtienne Carriere 
97e084583eSEtienne Carriere 	return client;
98e084583eSEtienne Carriere }
99e084583eSEtienne Carriere 
100e084583eSEtienne Carriere void unregister_client(struct pkcs11_client *client)
101e084583eSEtienne Carriere {
1026e4f8f17SEtienne Carriere 	struct pkcs11_session *session = NULL;
1036e4f8f17SEtienne Carriere 	struct pkcs11_session *next = NULL;
1046e4f8f17SEtienne Carriere 
105e084583eSEtienne Carriere 	if (!client) {
106e084583eSEtienne Carriere 		EMSG("Invalid TEE session handle");
107e084583eSEtienne Carriere 		return;
108e084583eSEtienne Carriere 	}
109e084583eSEtienne Carriere 
1106e4f8f17SEtienne Carriere 	TAILQ_FOREACH_SAFE(session, &client->session_list, link, next)
1116e4f8f17SEtienne Carriere 		close_ck_session(session);
1126e4f8f17SEtienne Carriere 
113e084583eSEtienne Carriere 	TAILQ_REMOVE(&pkcs11_client_list, client, link);
114e084583eSEtienne Carriere 	handle_db_destroy(&client->session_handle_db);
115e084583eSEtienne Carriere 	TEE_Free(client);
116e084583eSEtienne Carriere }
117e084583eSEtienne Carriere 
118c84ccd0aSEtienne Carriere static TEE_Result pkcs11_token_init(unsigned int id)
119c84ccd0aSEtienne Carriere {
120c84ccd0aSEtienne Carriere 	struct ck_token *token = init_persistent_db(id);
121c84ccd0aSEtienne Carriere 
122c84ccd0aSEtienne Carriere 	if (!token)
123c84ccd0aSEtienne Carriere 		return TEE_ERROR_SECURITY;
124c84ccd0aSEtienne Carriere 
125c84ccd0aSEtienne Carriere 	if (token->state == PKCS11_TOKEN_RESET) {
126c84ccd0aSEtienne Carriere 		/* As per PKCS#11 spec, token resets to read/write state */
127c84ccd0aSEtienne Carriere 		token->state = PKCS11_TOKEN_READ_WRITE;
128c84ccd0aSEtienne Carriere 		token->session_count = 0;
129c84ccd0aSEtienne Carriere 		token->rw_session_count = 0;
130c84ccd0aSEtienne Carriere 	}
131c84ccd0aSEtienne Carriere 
132c84ccd0aSEtienne Carriere 	return TEE_SUCCESS;
133c84ccd0aSEtienne Carriere }
134c84ccd0aSEtienne Carriere 
135c84ccd0aSEtienne Carriere TEE_Result pkcs11_init(void)
136c84ccd0aSEtienne Carriere {
137c84ccd0aSEtienne Carriere 	unsigned int id = 0;
138c84ccd0aSEtienne Carriere 	TEE_Result ret = TEE_ERROR_GENERIC;
139c84ccd0aSEtienne Carriere 
140c84ccd0aSEtienne Carriere 	for (id = 0; id < TOKEN_COUNT; id++) {
141c84ccd0aSEtienne Carriere 		ret = pkcs11_token_init(id);
142c84ccd0aSEtienne Carriere 		if (ret)
143e084583eSEtienne Carriere 			break;
144c84ccd0aSEtienne Carriere 	}
145c84ccd0aSEtienne Carriere 
146c84ccd0aSEtienne Carriere 	return ret;
147c84ccd0aSEtienne Carriere }
148c84ccd0aSEtienne Carriere 
149c84ccd0aSEtienne Carriere void pkcs11_deinit(void)
150c84ccd0aSEtienne Carriere {
151c84ccd0aSEtienne Carriere 	unsigned int id = 0;
152c84ccd0aSEtienne Carriere 
153c84ccd0aSEtienne Carriere 	for (id = 0; id < TOKEN_COUNT; id++)
154c84ccd0aSEtienne Carriere 		close_persistent_db(get_token(id));
155c84ccd0aSEtienne Carriere }
15622ac6984SEtienne Carriere 
157512cbf1dSJens Wiklander /*
158512cbf1dSJens Wiklander  * Currently no support for dual operations.
159512cbf1dSJens Wiklander  */
160512cbf1dSJens Wiklander enum pkcs11_rc set_processing_state(struct pkcs11_session *session,
161512cbf1dSJens Wiklander 				    enum processing_func function,
162512cbf1dSJens Wiklander 				    struct pkcs11_object *obj1,
163512cbf1dSJens Wiklander 				    struct pkcs11_object *obj2)
164512cbf1dSJens Wiklander {
165512cbf1dSJens Wiklander 	enum pkcs11_proc_state state = PKCS11_SESSION_READY;
166512cbf1dSJens Wiklander 	struct active_processing *proc = NULL;
167512cbf1dSJens Wiklander 
168512cbf1dSJens Wiklander 	if (session->processing)
169512cbf1dSJens Wiklander 		return PKCS11_CKR_OPERATION_ACTIVE;
170512cbf1dSJens Wiklander 
171512cbf1dSJens Wiklander 	switch (function) {
172512cbf1dSJens Wiklander 	case PKCS11_FUNCTION_ENCRYPT:
173512cbf1dSJens Wiklander 		state = PKCS11_SESSION_ENCRYPTING;
174512cbf1dSJens Wiklander 		break;
175512cbf1dSJens Wiklander 	case PKCS11_FUNCTION_DECRYPT:
176512cbf1dSJens Wiklander 		state = PKCS11_SESSION_DECRYPTING;
177512cbf1dSJens Wiklander 		break;
178512cbf1dSJens Wiklander 	case PKCS11_FUNCTION_SIGN:
179512cbf1dSJens Wiklander 		state = PKCS11_SESSION_SIGNING;
180512cbf1dSJens Wiklander 		break;
181512cbf1dSJens Wiklander 	case PKCS11_FUNCTION_VERIFY:
182512cbf1dSJens Wiklander 		state = PKCS11_SESSION_VERIFYING;
183512cbf1dSJens Wiklander 		break;
184512cbf1dSJens Wiklander 	case PKCS11_FUNCTION_DIGEST:
185512cbf1dSJens Wiklander 		state = PKCS11_SESSION_DIGESTING;
186512cbf1dSJens Wiklander 		break;
187512cbf1dSJens Wiklander 	case PKCS11_FUNCTION_DERIVE:
188512cbf1dSJens Wiklander 		state = PKCS11_SESSION_READY;
189512cbf1dSJens Wiklander 		break;
190512cbf1dSJens Wiklander 	default:
191512cbf1dSJens Wiklander 		TEE_Panic(function);
192512cbf1dSJens Wiklander 		return -1;
193512cbf1dSJens Wiklander 	}
194512cbf1dSJens Wiklander 
195512cbf1dSJens Wiklander 	proc = TEE_Malloc(sizeof(*proc), TEE_MALLOC_FILL_ZERO);
196512cbf1dSJens Wiklander 	if (!proc)
197512cbf1dSJens Wiklander 		return PKCS11_CKR_DEVICE_MEMORY;
198512cbf1dSJens Wiklander 
199512cbf1dSJens Wiklander 	/* Boolean are default to false and pointers to NULL */
200512cbf1dSJens Wiklander 	proc->state = state;
201512cbf1dSJens Wiklander 	proc->tee_op_handle = TEE_HANDLE_NULL;
202512cbf1dSJens Wiklander 
203512cbf1dSJens Wiklander 	if (obj1 && get_bool(obj1->attributes, PKCS11_CKA_ALWAYS_AUTHENTICATE))
204512cbf1dSJens Wiklander 		proc->always_authen = true;
205512cbf1dSJens Wiklander 
206512cbf1dSJens Wiklander 	if (obj2 && get_bool(obj2->attributes, PKCS11_CKA_ALWAYS_AUTHENTICATE))
207512cbf1dSJens Wiklander 		proc->always_authen = true;
208512cbf1dSJens Wiklander 
209512cbf1dSJens Wiklander 	session->processing = proc;
210512cbf1dSJens Wiklander 
211512cbf1dSJens Wiklander 	return PKCS11_CKR_OK;
212512cbf1dSJens Wiklander }
213512cbf1dSJens Wiklander 
2144daf39b3SJens Wiklander enum pkcs11_rc entry_ck_slot_list(uint32_t ptypes, TEE_Param *params)
21522ac6984SEtienne Carriere {
21622ac6984SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
21722ac6984SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
21822ac6984SEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
21922ac6984SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
22039b43b78SJens Wiklander 	TEE_Param *out = params + 2;
22122ac6984SEtienne Carriere 	uint32_t token_id = 0;
22222ac6984SEtienne Carriere 	const size_t out_size = sizeof(token_id) * TOKEN_COUNT;
22322ac6984SEtienne Carriere 	uint8_t *id = NULL;
22422ac6984SEtienne Carriere 
22522ac6984SEtienne Carriere 	if (ptypes != exp_pt ||
22622ac6984SEtienne Carriere 	    params[0].memref.size != TEE_PARAM0_SIZE_MIN)
22722ac6984SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
22822ac6984SEtienne Carriere 
22922ac6984SEtienne Carriere 	if (out->memref.size < out_size) {
23022ac6984SEtienne Carriere 		out->memref.size = out_size;
23122ac6984SEtienne Carriere 
23222ac6984SEtienne Carriere 		if (out->memref.buffer)
23322ac6984SEtienne Carriere 			return PKCS11_CKR_BUFFER_TOO_SMALL;
23422ac6984SEtienne Carriere 		else
23522ac6984SEtienne Carriere 			return PKCS11_CKR_OK;
23622ac6984SEtienne Carriere 	}
23722ac6984SEtienne Carriere 
23822ac6984SEtienne Carriere 	for (token_id = 0, id = out->memref.buffer; token_id < TOKEN_COUNT;
23922ac6984SEtienne Carriere 	     token_id++, id += sizeof(token_id))
24022ac6984SEtienne Carriere 		TEE_MemMove(id, &token_id, sizeof(token_id));
24122ac6984SEtienne Carriere 
24222ac6984SEtienne Carriere 	out->memref.size = out_size;
24322ac6984SEtienne Carriere 
24422ac6984SEtienne Carriere 	return PKCS11_CKR_OK;
24522ac6984SEtienne Carriere }
246ce94efefSEtienne Carriere 
247b3ac5035SEtienne Carriere static void pad_str(uint8_t *str, size_t size)
248b3ac5035SEtienne Carriere {
249b3ac5035SEtienne Carriere 	int n = strnlen((char *)str, size);
250b3ac5035SEtienne Carriere 
251b3ac5035SEtienne Carriere 	TEE_MemFill(str + n, ' ', size - n);
252b3ac5035SEtienne Carriere }
253b3ac5035SEtienne Carriere 
254d628ebd9SEtienne Carriere static void set_token_description(struct pkcs11_slot_info *info)
255d628ebd9SEtienne Carriere {
256d628ebd9SEtienne Carriere 	char desc[sizeof(info->slot_description) + 1] = { 0 };
257d628ebd9SEtienne Carriere 	TEE_UUID dev_id = { };
258d628ebd9SEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
259d628ebd9SEtienne Carriere 	int n = 0;
260d628ebd9SEtienne Carriere 
261d628ebd9SEtienne Carriere 	res = TEE_GetPropertyAsUUID(TEE_PROPSET_TEE_IMPLEMENTATION,
262d628ebd9SEtienne Carriere 				    "gpd.tee.deviceID", &dev_id);
263d628ebd9SEtienne Carriere 	if (res == TEE_SUCCESS) {
264d628ebd9SEtienne Carriere 		n = snprintk(desc, sizeof(desc), PKCS11_SLOT_DESCRIPTION
265d628ebd9SEtienne Carriere 			     " - TEE UUID %pUl", (void *)&dev_id);
266d628ebd9SEtienne Carriere 	} else {
267d628ebd9SEtienne Carriere 		n = snprintf(desc, sizeof(desc), PKCS11_SLOT_DESCRIPTION
268d628ebd9SEtienne Carriere 			     " - No TEE UUID");
269d628ebd9SEtienne Carriere 	}
270d628ebd9SEtienne Carriere 	if (n < 0 || n >= (int)sizeof(desc))
271d628ebd9SEtienne Carriere 		TEE_Panic(0);
272d628ebd9SEtienne Carriere 
273d628ebd9SEtienne Carriere 	TEE_MemMove(info->slot_description, desc, n);
274d628ebd9SEtienne Carriere 	pad_str(info->slot_description, sizeof(info->slot_description));
275d628ebd9SEtienne Carriere }
276d628ebd9SEtienne Carriere 
2774daf39b3SJens Wiklander enum pkcs11_rc entry_ck_slot_info(uint32_t ptypes, TEE_Param *params)
278ce94efefSEtienne Carriere {
279ce94efefSEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
280ce94efefSEtienne Carriere 						TEE_PARAM_TYPE_NONE,
281ce94efefSEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
282ce94efefSEtienne Carriere 						TEE_PARAM_TYPE_NONE);
28339b43b78SJens Wiklander 	TEE_Param *ctrl = params;
28439b43b78SJens Wiklander 	TEE_Param *out = params + 2;
2854daf39b3SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
286ce94efefSEtienne Carriere 	struct serialargs ctrlargs = { };
287ce94efefSEtienne Carriere 	uint32_t token_id = 0;
288ce94efefSEtienne Carriere 	struct pkcs11_slot_info info = {
289ce94efefSEtienne Carriere 		.slot_description = PKCS11_SLOT_DESCRIPTION,
290ce94efefSEtienne Carriere 		.manufacturer_id = PKCS11_SLOT_MANUFACTURER,
291ce94efefSEtienne Carriere 		.flags = PKCS11_CKFS_TOKEN_PRESENT,
292ce94efefSEtienne Carriere 		.hardware_version = PKCS11_SLOT_HW_VERSION,
293ce94efefSEtienne Carriere 		.firmware_version = PKCS11_SLOT_FW_VERSION,
294ce94efefSEtienne Carriere 	};
295ce94efefSEtienne Carriere 
296ce94efefSEtienne Carriere 	COMPILE_TIME_ASSERT(sizeof(PKCS11_SLOT_DESCRIPTION) <=
297ce94efefSEtienne Carriere 			    sizeof(info.slot_description));
298ce94efefSEtienne Carriere 	COMPILE_TIME_ASSERT(sizeof(PKCS11_SLOT_MANUFACTURER) <=
299ce94efefSEtienne Carriere 			    sizeof(info.manufacturer_id));
300ce94efefSEtienne Carriere 
301ce94efefSEtienne Carriere 	if (ptypes != exp_pt || out->memref.size != sizeof(info))
302ce94efefSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
303ce94efefSEtienne Carriere 
304ce94efefSEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
305ce94efefSEtienne Carriere 
3064daf39b3SJens Wiklander 	rc = serialargs_get(&ctrlargs, &token_id, sizeof(token_id));
3074daf39b3SJens Wiklander 	if (rc)
3084daf39b3SJens Wiklander 		return rc;
309ce94efefSEtienne Carriere 
310ce94efefSEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
311ce94efefSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
312ce94efefSEtienne Carriere 
31329b0949aSEtienne Carriere 	if (!get_token(token_id))
314ce94efefSEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
315ce94efefSEtienne Carriere 
316d628ebd9SEtienne Carriere 	set_token_description(&info);
317d628ebd9SEtienne Carriere 
318b3ac5035SEtienne Carriere 	pad_str(info.manufacturer_id, sizeof(info.manufacturer_id));
319ce94efefSEtienne Carriere 
320ce94efefSEtienne Carriere 	out->memref.size = sizeof(info);
321ce94efefSEtienne Carriere 	TEE_MemMove(out->memref.buffer, &info, out->memref.size);
322ce94efefSEtienne Carriere 
323ce94efefSEtienne Carriere 	return PKCS11_CKR_OK;
324ce94efefSEtienne Carriere }
325030e7392SEtienne Carriere 
3264daf39b3SJens Wiklander enum pkcs11_rc entry_ck_token_info(uint32_t ptypes, TEE_Param *params)
327030e7392SEtienne Carriere {
328030e7392SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
329030e7392SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
330030e7392SEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
331030e7392SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
33239b43b78SJens Wiklander 	TEE_Param *ctrl = params;
33339b43b78SJens Wiklander 	TEE_Param *out = params + 2;
3344daf39b3SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
335030e7392SEtienne Carriere 	struct serialargs ctrlargs = { };
336030e7392SEtienne Carriere 	uint32_t token_id = 0;
337030e7392SEtienne Carriere 	struct ck_token *token = NULL;
338030e7392SEtienne Carriere 	struct pkcs11_token_info info = {
339030e7392SEtienne Carriere 		.manufacturer_id = PKCS11_TOKEN_MANUFACTURER,
340030e7392SEtienne Carriere 		.model = PKCS11_TOKEN_MODEL,
341030e7392SEtienne Carriere 		.max_session_count = UINT32_MAX,
342030e7392SEtienne Carriere 		.max_rw_session_count = UINT32_MAX,
343030e7392SEtienne Carriere 		.max_pin_len = PKCS11_TOKEN_PIN_SIZE_MAX,
344030e7392SEtienne Carriere 		.min_pin_len = PKCS11_TOKEN_PIN_SIZE_MIN,
345030e7392SEtienne Carriere 		.total_public_memory = UINT32_MAX,
346030e7392SEtienne Carriere 		.free_public_memory = UINT32_MAX,
347030e7392SEtienne Carriere 		.total_private_memory = UINT32_MAX,
348030e7392SEtienne Carriere 		.free_private_memory = UINT32_MAX,
349030e7392SEtienne Carriere 		.hardware_version = PKCS11_TOKEN_HW_VERSION,
350030e7392SEtienne Carriere 		.firmware_version = PKCS11_TOKEN_FW_VERSION,
351030e7392SEtienne Carriere 	};
35202b4d42aSEtienne Carriere 	char sn[sizeof(info.serial_number) + 1] = { 0 };
35302b4d42aSEtienne Carriere 	int n = 0;
354030e7392SEtienne Carriere 
355030e7392SEtienne Carriere 	if (ptypes != exp_pt || out->memref.size != sizeof(info))
356030e7392SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
357030e7392SEtienne Carriere 
358030e7392SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
359030e7392SEtienne Carriere 
3604daf39b3SJens Wiklander 	rc = serialargs_get(&ctrlargs, &token_id, sizeof(token_id));
3614daf39b3SJens Wiklander 	if (rc)
3624daf39b3SJens Wiklander 		return rc;
363030e7392SEtienne Carriere 
364030e7392SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
365030e7392SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
366030e7392SEtienne Carriere 
367030e7392SEtienne Carriere 	token = get_token(token_id);
368030e7392SEtienne Carriere 	if (!token)
369030e7392SEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
370030e7392SEtienne Carriere 
371030e7392SEtienne Carriere 	pad_str(info.manufacturer_id, sizeof(info.manufacturer_id));
372030e7392SEtienne Carriere 	pad_str(info.model, sizeof(info.model));
37302b4d42aSEtienne Carriere 
37402b4d42aSEtienne Carriere 	n = snprintf(sn, sizeof(sn), "%0*"PRIu32,
37502b4d42aSEtienne Carriere 		     (int)sizeof(info.serial_number), token_id);
37602b4d42aSEtienne Carriere 	if (n != (int)sizeof(info.serial_number))
37702b4d42aSEtienne Carriere 		TEE_Panic(0);
37802b4d42aSEtienne Carriere 
37902b4d42aSEtienne Carriere 	TEE_MemMove(info.serial_number, sn, sizeof(info.serial_number));
380030e7392SEtienne Carriere 	pad_str(info.serial_number, sizeof(info.serial_number));
381030e7392SEtienne Carriere 
382030e7392SEtienne Carriere 	TEE_MemMove(info.label, token->db_main->label, sizeof(info.label));
383030e7392SEtienne Carriere 
384030e7392SEtienne Carriere 	info.flags = token->db_main->flags;
385030e7392SEtienne Carriere 	info.session_count = token->session_count;
386030e7392SEtienne Carriere 	info.rw_session_count = token->rw_session_count;
387030e7392SEtienne Carriere 
388030e7392SEtienne Carriere 	TEE_MemMove(out->memref.buffer, &info, sizeof(info));
389030e7392SEtienne Carriere 
390030e7392SEtienne Carriere 	return PKCS11_CKR_OK;
391030e7392SEtienne Carriere }
3926f74919dSEtienne Carriere 
3936f74919dSEtienne Carriere static void dmsg_print_supported_mechanism(unsigned int token_id __maybe_unused,
3946f74919dSEtienne Carriere 					   uint32_t *array __maybe_unused,
3956f74919dSEtienne Carriere 					   size_t count __maybe_unused)
3966f74919dSEtienne Carriere {
3976f74919dSEtienne Carriere 	size_t __maybe_unused n = 0;
3986f74919dSEtienne Carriere 
3996f74919dSEtienne Carriere 	if (TRACE_LEVEL < TRACE_DEBUG)
4006f74919dSEtienne Carriere 		return;
4016f74919dSEtienne Carriere 
4026f74919dSEtienne Carriere 	for (n = 0; n < count; n++)
4036f74919dSEtienne Carriere 		DMSG("PKCS11 token %"PRIu32": mechanism 0x%04"PRIx32": %s",
4046f74919dSEtienne Carriere 		     token_id, array[n], id2str_mechanism(array[n]));
4056f74919dSEtienne Carriere }
4066f74919dSEtienne Carriere 
4074daf39b3SJens Wiklander enum pkcs11_rc entry_ck_token_mecha_ids(uint32_t ptypes, TEE_Param *params)
4086f74919dSEtienne Carriere {
4096f74919dSEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
4106f74919dSEtienne Carriere 						TEE_PARAM_TYPE_NONE,
4116f74919dSEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
4126f74919dSEtienne Carriere 						TEE_PARAM_TYPE_NONE);
41339b43b78SJens Wiklander 	TEE_Param *ctrl = params;
41439b43b78SJens Wiklander 	TEE_Param *out = params + 2;
4154daf39b3SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
4166f74919dSEtienne Carriere 	struct serialargs ctrlargs = { };
4176f74919dSEtienne Carriere 	uint32_t token_id = 0;
4186f74919dSEtienne Carriere 	struct ck_token __maybe_unused *token = NULL;
4196f74919dSEtienne Carriere 	size_t count = 0;
4206f74919dSEtienne Carriere 	uint32_t *array = NULL;
4216f74919dSEtienne Carriere 
4226f74919dSEtienne Carriere 	if (ptypes != exp_pt)
4236f74919dSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
4246f74919dSEtienne Carriere 
4256f74919dSEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
4266f74919dSEtienne Carriere 
4274daf39b3SJens Wiklander 	rc = serialargs_get(&ctrlargs, &token_id, sizeof(token_id));
4284daf39b3SJens Wiklander 	if (rc)
4294daf39b3SJens Wiklander 		return rc;
4306f74919dSEtienne Carriere 
4316f74919dSEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
4326f74919dSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
4336f74919dSEtienne Carriere 
4346f74919dSEtienne Carriere 	token = get_token(token_id);
4356f74919dSEtienne Carriere 	if (!token)
4366f74919dSEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
4376f74919dSEtienne Carriere 
4386f74919dSEtienne Carriere 	count = out->memref.size / sizeof(*array);
4396f74919dSEtienne Carriere 	array = tee_malloc_mechanism_list(&count);
4406f74919dSEtienne Carriere 
4416f74919dSEtienne Carriere 	if (out->memref.size < count * sizeof(*array)) {
4426f74919dSEtienne Carriere 		assert(!array);
4436f74919dSEtienne Carriere 		out->memref.size = count * sizeof(*array);
4446459f267SEtienne Carriere 		if (out->memref.buffer)
4456f74919dSEtienne Carriere 			return PKCS11_CKR_BUFFER_TOO_SMALL;
4466459f267SEtienne Carriere 		else
4476459f267SEtienne Carriere 			return PKCS11_CKR_OK;
4486f74919dSEtienne Carriere 	}
4496f74919dSEtienne Carriere 
4506f74919dSEtienne Carriere 	if (!array)
4516f74919dSEtienne Carriere 		return PKCS11_CKR_DEVICE_MEMORY;
4526f74919dSEtienne Carriere 
4536f74919dSEtienne Carriere 	dmsg_print_supported_mechanism(token_id, array, count);
4546f74919dSEtienne Carriere 
4556f74919dSEtienne Carriere 	out->memref.size = count * sizeof(*array);
4566f74919dSEtienne Carriere 	TEE_MemMove(out->memref.buffer, array, out->memref.size);
4576f74919dSEtienne Carriere 
4586f74919dSEtienne Carriere 	TEE_Free(array);
4596f74919dSEtienne Carriere 
4604daf39b3SJens Wiklander 	return rc;
4616f74919dSEtienne Carriere }
4621d3ebedbSEtienne Carriere 
4634daf39b3SJens Wiklander enum pkcs11_rc entry_ck_token_mecha_info(uint32_t ptypes, TEE_Param *params)
4641d3ebedbSEtienne Carriere {
4651d3ebedbSEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
4661d3ebedbSEtienne Carriere 						TEE_PARAM_TYPE_NONE,
4671d3ebedbSEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
4681d3ebedbSEtienne Carriere 						TEE_PARAM_TYPE_NONE);
46939b43b78SJens Wiklander 	TEE_Param *ctrl = params;
47039b43b78SJens Wiklander 	TEE_Param *out = params + 2;
4714daf39b3SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
4721d3ebedbSEtienne Carriere 	struct serialargs ctrlargs = { };
4731d3ebedbSEtienne Carriere 	uint32_t token_id = 0;
4741d3ebedbSEtienne Carriere 	uint32_t type = 0;
4751d3ebedbSEtienne Carriere 	struct ck_token *token = NULL;
4761d3ebedbSEtienne Carriere 	struct pkcs11_mechanism_info info = { };
4771d3ebedbSEtienne Carriere 
4781d3ebedbSEtienne Carriere 	if (ptypes != exp_pt || out->memref.size != sizeof(info))
4791d3ebedbSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
4801d3ebedbSEtienne Carriere 
4811d3ebedbSEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
4821d3ebedbSEtienne Carriere 
4834daf39b3SJens Wiklander 	rc = serialargs_get(&ctrlargs, &token_id, sizeof(uint32_t));
4844daf39b3SJens Wiklander 	if (rc)
4854daf39b3SJens Wiklander 		return rc;
4861d3ebedbSEtienne Carriere 
4874daf39b3SJens Wiklander 	rc = serialargs_get(&ctrlargs, &type, sizeof(uint32_t));
4884daf39b3SJens Wiklander 	if (rc)
4894daf39b3SJens Wiklander 		return rc;
4901d3ebedbSEtienne Carriere 
4911d3ebedbSEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
4921d3ebedbSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
4931d3ebedbSEtienne Carriere 
4941d3ebedbSEtienne Carriere 	token = get_token(token_id);
4951d3ebedbSEtienne Carriere 	if (!token)
4961d3ebedbSEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
4971d3ebedbSEtienne Carriere 
4981d3ebedbSEtienne Carriere 	if (!mechanism_is_valid(type))
4991d3ebedbSEtienne Carriere 		return PKCS11_CKR_MECHANISM_INVALID;
5001d3ebedbSEtienne Carriere 
5011d3ebedbSEtienne Carriere 	info.flags = mechanism_supported_flags(type);
5021d3ebedbSEtienne Carriere 
50378adf52fSEtienne Carriere 	mechanism_supported_key_sizes(type, &info.min_key_size,
5041d3ebedbSEtienne Carriere 				      &info.max_key_size);
5051d3ebedbSEtienne Carriere 
5061d3ebedbSEtienne Carriere 	TEE_MemMove(out->memref.buffer, &info, sizeof(info));
5071d3ebedbSEtienne Carriere 
5081d3ebedbSEtienne Carriere 	DMSG("PKCS11 token %"PRIu32": mechanism 0x%"PRIx32" info",
5091d3ebedbSEtienne Carriere 	     token_id, type);
5101d3ebedbSEtienne Carriere 
5111d3ebedbSEtienne Carriere 	return PKCS11_CKR_OK;
5121d3ebedbSEtienne Carriere }
5136e4f8f17SEtienne Carriere 
5146e4f8f17SEtienne Carriere /* Select the ReadOnly or ReadWrite state for session login state */
5156e4f8f17SEtienne Carriere static void set_session_state(struct pkcs11_client *client,
5166e4f8f17SEtienne Carriere 			      struct pkcs11_session *session, bool readonly)
5176e4f8f17SEtienne Carriere {
5186e4f8f17SEtienne Carriere 	struct pkcs11_session *sess = NULL;
5196e4f8f17SEtienne Carriere 	enum pkcs11_session_state state = PKCS11_CKS_RO_PUBLIC_SESSION;
5206e4f8f17SEtienne Carriere 
5216e4f8f17SEtienne Carriere 	/* Default to public session if no session already registered */
5226e4f8f17SEtienne Carriere 	if (readonly)
5236e4f8f17SEtienne Carriere 		state = PKCS11_CKS_RO_PUBLIC_SESSION;
5246e4f8f17SEtienne Carriere 	else
5256e4f8f17SEtienne Carriere 		state = PKCS11_CKS_RW_PUBLIC_SESSION;
5266e4f8f17SEtienne Carriere 
5276e4f8f17SEtienne Carriere 	/*
5286e4f8f17SEtienne Carriere 	 * No need to check all client sessions, the first found in
5296e4f8f17SEtienne Carriere 	 * target token gives client login configuration.
5306e4f8f17SEtienne Carriere 	 */
5316e4f8f17SEtienne Carriere 	TAILQ_FOREACH(sess, &client->session_list, link) {
5326e4f8f17SEtienne Carriere 		assert(sess != session);
5336e4f8f17SEtienne Carriere 
5346e4f8f17SEtienne Carriere 		if (sess->token == session->token) {
5356e4f8f17SEtienne Carriere 			switch (sess->state) {
5366e4f8f17SEtienne Carriere 			case PKCS11_CKS_RW_PUBLIC_SESSION:
5376e4f8f17SEtienne Carriere 			case PKCS11_CKS_RO_PUBLIC_SESSION:
5386e4f8f17SEtienne Carriere 				if (readonly)
5396e4f8f17SEtienne Carriere 					state = PKCS11_CKS_RO_PUBLIC_SESSION;
5406e4f8f17SEtienne Carriere 				else
5416e4f8f17SEtienne Carriere 					state = PKCS11_CKS_RW_PUBLIC_SESSION;
5426e4f8f17SEtienne Carriere 				break;
5436e4f8f17SEtienne Carriere 			case PKCS11_CKS_RO_USER_FUNCTIONS:
5446e4f8f17SEtienne Carriere 			case PKCS11_CKS_RW_USER_FUNCTIONS:
5456e4f8f17SEtienne Carriere 				if (readonly)
5466e4f8f17SEtienne Carriere 					state = PKCS11_CKS_RO_USER_FUNCTIONS;
5476e4f8f17SEtienne Carriere 				else
5486e4f8f17SEtienne Carriere 					state = PKCS11_CKS_RW_USER_FUNCTIONS;
5496e4f8f17SEtienne Carriere 				break;
5506e4f8f17SEtienne Carriere 			case PKCS11_CKS_RW_SO_FUNCTIONS:
5516e4f8f17SEtienne Carriere 				if (readonly)
5526e4f8f17SEtienne Carriere 					TEE_Panic(0);
5536e4f8f17SEtienne Carriere 				else
5546e4f8f17SEtienne Carriere 					state = PKCS11_CKS_RW_SO_FUNCTIONS;
5556e4f8f17SEtienne Carriere 				break;
5566e4f8f17SEtienne Carriere 			default:
5576e4f8f17SEtienne Carriere 				TEE_Panic(0);
5586e4f8f17SEtienne Carriere 			}
5596e4f8f17SEtienne Carriere 			break;
5606e4f8f17SEtienne Carriere 		}
5616e4f8f17SEtienne Carriere 	}
5626e4f8f17SEtienne Carriere 
5636e4f8f17SEtienne Carriere 	session->state = state;
5646e4f8f17SEtienne Carriere }
5656e4f8f17SEtienne Carriere 
5664daf39b3SJens Wiklander enum pkcs11_rc entry_ck_open_session(struct pkcs11_client *client,
5676e4f8f17SEtienne Carriere 				     uint32_t ptypes, TEE_Param *params)
5686e4f8f17SEtienne Carriere {
5696e4f8f17SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
5706e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
5716e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
5726e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
57339b43b78SJens Wiklander 	TEE_Param *ctrl = params;
57439b43b78SJens Wiklander 	TEE_Param *out = params + 2;
5754daf39b3SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
5766e4f8f17SEtienne Carriere 	struct serialargs ctrlargs = { };
5776e4f8f17SEtienne Carriere 	uint32_t token_id = 0;
5786e4f8f17SEtienne Carriere 	uint32_t flags = 0;
5796e4f8f17SEtienne Carriere 	struct ck_token *token = NULL;
5806e4f8f17SEtienne Carriere 	struct pkcs11_session *session = NULL;
5816e4f8f17SEtienne Carriere 	bool readonly = false;
5826e4f8f17SEtienne Carriere 
5836e4f8f17SEtienne Carriere 	if (!client || ptypes != exp_pt ||
5846e4f8f17SEtienne Carriere 	    out->memref.size != sizeof(session->handle))
5856e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
5866e4f8f17SEtienne Carriere 
5876e4f8f17SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
5886e4f8f17SEtienne Carriere 
5894daf39b3SJens Wiklander 	rc = serialargs_get(&ctrlargs, &token_id, sizeof(token_id));
5904daf39b3SJens Wiklander 	if (rc)
5914daf39b3SJens Wiklander 		return rc;
5926e4f8f17SEtienne Carriere 
5934daf39b3SJens Wiklander 	rc = serialargs_get(&ctrlargs, &flags, sizeof(flags));
5944daf39b3SJens Wiklander 	if (rc)
5954daf39b3SJens Wiklander 		return rc;
5966e4f8f17SEtienne Carriere 
5976e4f8f17SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
5986e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
5996e4f8f17SEtienne Carriere 
6006e4f8f17SEtienne Carriere 	token = get_token(token_id);
6016e4f8f17SEtienne Carriere 	if (!token)
6026e4f8f17SEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
6036e4f8f17SEtienne Carriere 
6046e4f8f17SEtienne Carriere 	/* Sanitize session flags */
60508774c86SVesa Jääskeläinen 	if (!(flags & PKCS11_CKFSS_SERIAL_SESSION))
60608774c86SVesa Jääskeläinen 		return PKCS11_CKR_SESSION_PARALLEL_NOT_SUPPORTED;
60708774c86SVesa Jääskeläinen 
60808774c86SVesa Jääskeläinen 	if (flags & ~(PKCS11_CKFSS_RW_SESSION | PKCS11_CKFSS_SERIAL_SESSION))
6096e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
6106e4f8f17SEtienne Carriere 
6116e4f8f17SEtienne Carriere 	readonly = !(flags & PKCS11_CKFSS_RW_SESSION);
6126e4f8f17SEtienne Carriere 
6136e4f8f17SEtienne Carriere 	if (!readonly && token->state == PKCS11_TOKEN_READ_ONLY)
6146e4f8f17SEtienne Carriere 		return PKCS11_CKR_TOKEN_WRITE_PROTECTED;
6156e4f8f17SEtienne Carriere 
6166e4f8f17SEtienne Carriere 	if (readonly) {
6176e4f8f17SEtienne Carriere 		/* Specifically reject read-only session under SO login */
6186e4f8f17SEtienne Carriere 		TAILQ_FOREACH(session, &client->session_list, link)
6196e4f8f17SEtienne Carriere 			if (pkcs11_session_is_so(session))
6206e4f8f17SEtienne Carriere 				return PKCS11_CKR_SESSION_READ_WRITE_SO_EXISTS;
6216e4f8f17SEtienne Carriere 	}
6226e4f8f17SEtienne Carriere 
6236e4f8f17SEtienne Carriere 	session = TEE_Malloc(sizeof(*session), TEE_MALLOC_FILL_ZERO);
6246e4f8f17SEtienne Carriere 	if (!session)
6256e4f8f17SEtienne Carriere 		return PKCS11_CKR_DEVICE_MEMORY;
6266e4f8f17SEtienne Carriere 
6276e4f8f17SEtienne Carriere 	session->handle = handle_get(&client->session_handle_db, session);
6286e4f8f17SEtienne Carriere 	if (!session->handle) {
6296e4f8f17SEtienne Carriere 		TEE_Free(session);
6306e4f8f17SEtienne Carriere 		return PKCS11_CKR_DEVICE_MEMORY;
6316e4f8f17SEtienne Carriere 	}
6326e4f8f17SEtienne Carriere 
6336e4f8f17SEtienne Carriere 	session->token = token;
6346e4f8f17SEtienne Carriere 	session->client = client;
6356e4f8f17SEtienne Carriere 
636b56b3d07SJens Wiklander 	LIST_INIT(&session->object_list);
637b56b3d07SJens Wiklander 	handle_db_init(&session->object_handle_db);
638b56b3d07SJens Wiklander 
6396e4f8f17SEtienne Carriere 	set_session_state(client, session, readonly);
6406e4f8f17SEtienne Carriere 
6416e4f8f17SEtienne Carriere 	TAILQ_INSERT_HEAD(&client->session_list, session, link);
6426e4f8f17SEtienne Carriere 
6436e4f8f17SEtienne Carriere 	session->token->session_count++;
6446e4f8f17SEtienne Carriere 	if (!readonly)
6456e4f8f17SEtienne Carriere 		session->token->rw_session_count++;
6466e4f8f17SEtienne Carriere 
6476e4f8f17SEtienne Carriere 	TEE_MemMove(out->memref.buffer, &session->handle,
6486e4f8f17SEtienne Carriere 		    sizeof(session->handle));
6496e4f8f17SEtienne Carriere 
6506e4f8f17SEtienne Carriere 	DMSG("Open PKCS11 session %"PRIu32, session->handle);
6516e4f8f17SEtienne Carriere 
6526e4f8f17SEtienne Carriere 	return PKCS11_CKR_OK;
6536e4f8f17SEtienne Carriere }
6546e4f8f17SEtienne Carriere 
6556e4f8f17SEtienne Carriere static void close_ck_session(struct pkcs11_session *session)
6566e4f8f17SEtienne Carriere {
65755e6965cSEtienne Carriere 	release_active_processing(session);
65855e6965cSEtienne Carriere 
659b56b3d07SJens Wiklander 	/* No need to put object handles, the whole database is destroyed */
660b56b3d07SJens Wiklander 	while (!LIST_EMPTY(&session->object_list))
661b56b3d07SJens Wiklander 		destroy_object(session,
662b56b3d07SJens Wiklander 			       LIST_FIRST(&session->object_list), true);
663b56b3d07SJens Wiklander 
6646e4f8f17SEtienne Carriere 	TAILQ_REMOVE(&session->client->session_list, session, link);
6656e4f8f17SEtienne Carriere 	handle_put(&session->client->session_handle_db, session->handle);
666b56b3d07SJens Wiklander 	handle_db_destroy(&session->object_handle_db);
6676e4f8f17SEtienne Carriere 
6686e4f8f17SEtienne Carriere 	session->token->session_count--;
6696e4f8f17SEtienne Carriere 	if (pkcs11_session_is_read_write(session))
6706e4f8f17SEtienne Carriere 		session->token->rw_session_count--;
6716e4f8f17SEtienne Carriere 
6726e4f8f17SEtienne Carriere 	TEE_Free(session);
6736e4f8f17SEtienne Carriere 
6746e4f8f17SEtienne Carriere 	DMSG("Close PKCS11 session %"PRIu32, session->handle);
6756e4f8f17SEtienne Carriere }
6766e4f8f17SEtienne Carriere 
6774daf39b3SJens Wiklander enum pkcs11_rc entry_ck_close_session(struct pkcs11_client *client,
6786e4f8f17SEtienne Carriere 				      uint32_t ptypes, TEE_Param *params)
6796e4f8f17SEtienne Carriere {
6806e4f8f17SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
6816e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
6826e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
6836e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
68439b43b78SJens Wiklander 	TEE_Param *ctrl = params;
6854daf39b3SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
6866e4f8f17SEtienne Carriere 	struct serialargs ctrlargs = { };
6876e4f8f17SEtienne Carriere 	struct pkcs11_session *session = NULL;
6886e4f8f17SEtienne Carriere 
6896e4f8f17SEtienne Carriere 	if (!client || ptypes != exp_pt)
6906e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
6916e4f8f17SEtienne Carriere 
6926e4f8f17SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
6936e4f8f17SEtienne Carriere 
6944daf39b3SJens Wiklander 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
6954daf39b3SJens Wiklander 	if (rc)
6964daf39b3SJens Wiklander 		return rc;
6976e4f8f17SEtienne Carriere 
6986e4f8f17SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
6996e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
7006e4f8f17SEtienne Carriere 
7016e4f8f17SEtienne Carriere 	close_ck_session(session);
7026e4f8f17SEtienne Carriere 
7036e4f8f17SEtienne Carriere 	return PKCS11_CKR_OK;
7046e4f8f17SEtienne Carriere }
7056e4f8f17SEtienne Carriere 
7064daf39b3SJens Wiklander enum pkcs11_rc entry_ck_close_all_sessions(struct pkcs11_client *client,
7076e4f8f17SEtienne Carriere 					   uint32_t ptypes, TEE_Param *params)
7086e4f8f17SEtienne Carriere {
7096e4f8f17SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
7106e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
7116e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
7126e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
71339b43b78SJens Wiklander 	TEE_Param *ctrl = params;
7144daf39b3SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
7156e4f8f17SEtienne Carriere 	struct serialargs ctrlargs = { };
7166e4f8f17SEtienne Carriere 	uint32_t token_id = 0;
7176e4f8f17SEtienne Carriere 	struct ck_token *token = NULL;
7186e4f8f17SEtienne Carriere 	struct pkcs11_session *session = NULL;
7196e4f8f17SEtienne Carriere 	struct pkcs11_session *next = NULL;
7206e4f8f17SEtienne Carriere 
7216e4f8f17SEtienne Carriere 	if (!client || ptypes != exp_pt)
7226e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
7236e4f8f17SEtienne Carriere 
7246e4f8f17SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
7256e4f8f17SEtienne Carriere 
7264daf39b3SJens Wiklander 	rc = serialargs_get(&ctrlargs, &token_id, sizeof(uint32_t));
7274daf39b3SJens Wiklander 	if (rc)
7284daf39b3SJens Wiklander 		return rc;
7296e4f8f17SEtienne Carriere 
7306e4f8f17SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
7316e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
7326e4f8f17SEtienne Carriere 
7336e4f8f17SEtienne Carriere 	token = get_token(token_id);
7346e4f8f17SEtienne Carriere 	if (!token)
7356e4f8f17SEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
7366e4f8f17SEtienne Carriere 
7376e4f8f17SEtienne Carriere 	DMSG("Close all sessions for PKCS11 token %"PRIu32, token_id);
7386e4f8f17SEtienne Carriere 
7396e4f8f17SEtienne Carriere 	TAILQ_FOREACH_SAFE(session, &client->session_list, link, next)
7406e4f8f17SEtienne Carriere 		if (session->token == token)
7416e4f8f17SEtienne Carriere 			close_ck_session(session);
7426e4f8f17SEtienne Carriere 
7436e4f8f17SEtienne Carriere 	return PKCS11_CKR_OK;
7446e4f8f17SEtienne Carriere }
7456e4f8f17SEtienne Carriere 
7464daf39b3SJens Wiklander enum pkcs11_rc entry_ck_session_info(struct pkcs11_client *client,
7476e4f8f17SEtienne Carriere 				     uint32_t ptypes, TEE_Param *params)
7486e4f8f17SEtienne Carriere {
7496e4f8f17SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
7506e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
7516e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
7526e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
75339b43b78SJens Wiklander 	TEE_Param *ctrl = params;
75439b43b78SJens Wiklander 	TEE_Param *out = params + 2;
7554daf39b3SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
7566e4f8f17SEtienne Carriere 	struct serialargs ctrlargs = { };
7576e4f8f17SEtienne Carriere 	struct pkcs11_session *session = NULL;
7586e4f8f17SEtienne Carriere 	struct pkcs11_session_info info = {
7596e4f8f17SEtienne Carriere 		.flags = PKCS11_CKFSS_SERIAL_SESSION,
7606e4f8f17SEtienne Carriere 	};
7616e4f8f17SEtienne Carriere 
7626e4f8f17SEtienne Carriere 	if (!client || ptypes != exp_pt || out->memref.size != sizeof(info))
7636e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
7646e4f8f17SEtienne Carriere 
7656e4f8f17SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
7666e4f8f17SEtienne Carriere 
7674daf39b3SJens Wiklander 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
7684daf39b3SJens Wiklander 	if (rc)
7694daf39b3SJens Wiklander 		return rc;
7706e4f8f17SEtienne Carriere 
7716e4f8f17SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
7726e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
7736e4f8f17SEtienne Carriere 
7746e4f8f17SEtienne Carriere 	info.slot_id = get_token_id(session->token);
7756e4f8f17SEtienne Carriere 	info.state = session->state;
7766e4f8f17SEtienne Carriere 	if (pkcs11_session_is_read_write(session))
7776e4f8f17SEtienne Carriere 		info.flags |= PKCS11_CKFSS_RW_SESSION;
7786e4f8f17SEtienne Carriere 
7796e4f8f17SEtienne Carriere 	TEE_MemMove(out->memref.buffer, &info, sizeof(info));
7806e4f8f17SEtienne Carriere 
7816e4f8f17SEtienne Carriere 	DMSG("Get find on PKCS11 session %"PRIu32, session->handle);
7826e4f8f17SEtienne Carriere 
7836e4f8f17SEtienne Carriere 	return PKCS11_CKR_OK;
7846e4f8f17SEtienne Carriere }
785f485be04SJens Wiklander 
7864daf39b3SJens Wiklander enum pkcs11_rc entry_ck_token_initialize(uint32_t ptypes, TEE_Param *params)
787f485be04SJens Wiklander {
788f485be04SJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
789f485be04SJens Wiklander 						TEE_PARAM_TYPE_NONE,
790f485be04SJens Wiklander 						TEE_PARAM_TYPE_NONE,
791f485be04SJens Wiklander 						TEE_PARAM_TYPE_NONE);
792f485be04SJens Wiklander 	char label[PKCS11_TOKEN_LABEL_SIZE] = { 0 };
793f485be04SJens Wiklander 	struct pkcs11_client *client = NULL;
794f485be04SJens Wiklander 	struct pkcs11_session *sess = NULL;
795f485be04SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
796f485be04SJens Wiklander 	struct serialargs ctrlargs = { };
797f485be04SJens Wiklander 	struct ck_token *token = NULL;
798f485be04SJens Wiklander 	TEE_Param *ctrl = params;
799f485be04SJens Wiklander 	uint32_t token_id = 0;
800f485be04SJens Wiklander 	uint32_t pin_size = 0;
801f485be04SJens Wiklander 	void *pin = NULL;
802f485be04SJens Wiklander 
803f485be04SJens Wiklander 	if (ptypes != exp_pt)
804f485be04SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
805f485be04SJens Wiklander 
806f485be04SJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
807f485be04SJens Wiklander 
808f485be04SJens Wiklander 	rc = serialargs_get(&ctrlargs, &token_id, sizeof(uint32_t));
809f485be04SJens Wiklander 	if (rc)
810f485be04SJens Wiklander 		return rc;
811f485be04SJens Wiklander 
812f485be04SJens Wiklander 	rc = serialargs_get(&ctrlargs, &pin_size, sizeof(uint32_t));
813f485be04SJens Wiklander 	if (rc)
814f485be04SJens Wiklander 		return rc;
815f485be04SJens Wiklander 
816f485be04SJens Wiklander 	rc = serialargs_get(&ctrlargs, &label, PKCS11_TOKEN_LABEL_SIZE);
817f485be04SJens Wiklander 	if (rc)
818f485be04SJens Wiklander 		return rc;
819f485be04SJens Wiklander 
820f485be04SJens Wiklander 	rc = serialargs_get_ptr(&ctrlargs, &pin, pin_size);
821f485be04SJens Wiklander 	if (rc)
822f485be04SJens Wiklander 		return rc;
823f485be04SJens Wiklander 
824f485be04SJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs))
825f485be04SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
826f485be04SJens Wiklander 
827f485be04SJens Wiklander 	token = get_token(token_id);
828f485be04SJens Wiklander 	if (!token)
829f485be04SJens Wiklander 		return PKCS11_CKR_SLOT_ID_INVALID;
830f485be04SJens Wiklander 
831f485be04SJens Wiklander 	if (token->db_main->flags & PKCS11_CKFT_SO_PIN_LOCKED) {
832f485be04SJens Wiklander 		IMSG("Token %"PRIu32": SO PIN locked", token_id);
833f485be04SJens Wiklander 		return PKCS11_CKR_PIN_LOCKED;
834f485be04SJens Wiklander 	}
835f485be04SJens Wiklander 
836f485be04SJens Wiklander 	/* Check there's no open session on this token */
837f485be04SJens Wiklander 	TAILQ_FOREACH(client, &pkcs11_client_list, link)
838f485be04SJens Wiklander 		TAILQ_FOREACH(sess, &client->session_list, link)
839f485be04SJens Wiklander 			if (sess->token == token)
840f485be04SJens Wiklander 				return PKCS11_CKR_SESSION_EXISTS;
841f485be04SJens Wiklander 
842f485be04SJens Wiklander 	if (!token->db_main->so_pin_salt) {
843f485be04SJens Wiklander 		/*
844f485be04SJens Wiklander 		 * The spec doesn't permit returning
845f485be04SJens Wiklander 		 * PKCS11_CKR_PIN_LEN_RANGE for this function, take another
846f485be04SJens Wiklander 		 * error code.
847f485be04SJens Wiklander 		 */
848f485be04SJens Wiklander 		if (pin_size < PKCS11_TOKEN_PIN_SIZE_MIN ||
849f485be04SJens Wiklander 		    pin_size > PKCS11_TOKEN_PIN_SIZE_MAX)
850f485be04SJens Wiklander 			return PKCS11_CKR_ARGUMENTS_BAD;
851f485be04SJens Wiklander 
852f485be04SJens Wiklander 		rc = hash_pin(PKCS11_CKU_SO, pin, pin_size,
853f485be04SJens Wiklander 			      &token->db_main->so_pin_salt,
854f485be04SJens Wiklander 			      token->db_main->so_pin_hash);
855f485be04SJens Wiklander 		if (rc)
856f485be04SJens Wiklander 			return rc;
857f485be04SJens Wiklander 
858f485be04SJens Wiklander 		goto inited;
859f485be04SJens Wiklander 	}
860f485be04SJens Wiklander 
861f485be04SJens Wiklander 	rc = verify_pin(PKCS11_CKU_SO, pin, pin_size,
862f485be04SJens Wiklander 			token->db_main->so_pin_salt,
863f485be04SJens Wiklander 			token->db_main->so_pin_hash);
864f485be04SJens Wiklander 	if (rc) {
865f485be04SJens Wiklander 		unsigned int pin_count = 0;
866f485be04SJens Wiklander 
867f485be04SJens Wiklander 		if (rc != PKCS11_CKR_PIN_INCORRECT)
868f485be04SJens Wiklander 			return rc;
869f485be04SJens Wiklander 
870f485be04SJens Wiklander 		token->db_main->flags |= PKCS11_CKFT_SO_PIN_COUNT_LOW;
871f485be04SJens Wiklander 		token->db_main->so_pin_count++;
872f485be04SJens Wiklander 
873f485be04SJens Wiklander 		pin_count = token->db_main->so_pin_count;
874f485be04SJens Wiklander 		if (pin_count == PKCS11_TOKEN_SO_PIN_COUNT_MAX - 1)
875f485be04SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_SO_PIN_FINAL_TRY;
876f485be04SJens Wiklander 		if (pin_count == PKCS11_TOKEN_SO_PIN_COUNT_MAX)
877f485be04SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_SO_PIN_LOCKED;
878f485be04SJens Wiklander 
879f485be04SJens Wiklander 		update_persistent_db(token);
880f485be04SJens Wiklander 
881f485be04SJens Wiklander 		return PKCS11_CKR_PIN_INCORRECT;
882f485be04SJens Wiklander 	}
883f485be04SJens Wiklander 
884*12253e9eSVesa Jääskeläinen inited:
885*12253e9eSVesa Jääskeläinen 	/* Make sure SO PIN counters are zeroed */
886f485be04SJens Wiklander 	token->db_main->flags &= ~(PKCS11_CKFT_SO_PIN_COUNT_LOW |
887*12253e9eSVesa Jääskeläinen 				   PKCS11_CKFT_SO_PIN_FINAL_TRY |
888*12253e9eSVesa Jääskeläinen 				   PKCS11_CKFT_SO_PIN_LOCKED |
889*12253e9eSVesa Jääskeläinen 				   PKCS11_CKFT_SO_PIN_TO_BE_CHANGED);
890f485be04SJens Wiklander 	token->db_main->so_pin_count = 0;
891f485be04SJens Wiklander 
892f485be04SJens Wiklander 	TEE_MemMove(token->db_main->label, label, PKCS11_TOKEN_LABEL_SIZE);
893f485be04SJens Wiklander 	token->db_main->flags |= PKCS11_CKFT_TOKEN_INITIALIZED;
894f485be04SJens Wiklander 	/* Reset user PIN */
895f485be04SJens Wiklander 	token->db_main->user_pin_salt = 0;
896f485be04SJens Wiklander 	token->db_main->flags &= ~(PKCS11_CKFT_USER_PIN_INITIALIZED |
897f485be04SJens Wiklander 				   PKCS11_CKFT_USER_PIN_COUNT_LOW |
898f485be04SJens Wiklander 				   PKCS11_CKFT_USER_PIN_FINAL_TRY |
899f485be04SJens Wiklander 				   PKCS11_CKFT_USER_PIN_LOCKED |
900f485be04SJens Wiklander 				   PKCS11_CKFT_USER_PIN_TO_BE_CHANGED);
901f485be04SJens Wiklander 
902f485be04SJens Wiklander 	update_persistent_db(token);
903f485be04SJens Wiklander 
904f485be04SJens Wiklander 	IMSG("PKCS11 token %"PRIu32": initialized", token_id);
905f485be04SJens Wiklander 
906f485be04SJens Wiklander 	return PKCS11_CKR_OK;
907f485be04SJens Wiklander }
908e8dbd92cSJens Wiklander 
909e8dbd92cSJens Wiklander static enum pkcs11_rc set_pin(struct pkcs11_session *session,
910e8dbd92cSJens Wiklander 			      uint8_t *new_pin, size_t new_pin_size,
911e8dbd92cSJens Wiklander 			      enum pkcs11_user_type user_type)
912e8dbd92cSJens Wiklander {
913e8dbd92cSJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
914e8dbd92cSJens Wiklander 	uint32_t flags_clear = 0;
915e8dbd92cSJens Wiklander 	uint32_t flags_set = 0;
916e8dbd92cSJens Wiklander 
917e8dbd92cSJens Wiklander 	if (session->token->db_main->flags & PKCS11_CKFT_WRITE_PROTECTED)
918e8dbd92cSJens Wiklander 		return PKCS11_CKR_TOKEN_WRITE_PROTECTED;
919e8dbd92cSJens Wiklander 
920e8dbd92cSJens Wiklander 	if (!pkcs11_session_is_read_write(session))
921e8dbd92cSJens Wiklander 		return PKCS11_CKR_SESSION_READ_ONLY;
922e8dbd92cSJens Wiklander 
923e8dbd92cSJens Wiklander 	if (new_pin_size < PKCS11_TOKEN_PIN_SIZE_MIN ||
924e8dbd92cSJens Wiklander 	    new_pin_size > PKCS11_TOKEN_PIN_SIZE_MAX)
925e8dbd92cSJens Wiklander 		return PKCS11_CKR_PIN_LEN_RANGE;
926e8dbd92cSJens Wiklander 
927e8dbd92cSJens Wiklander 	switch (user_type) {
928e8dbd92cSJens Wiklander 	case PKCS11_CKU_SO:
929e8dbd92cSJens Wiklander 		rc = hash_pin(user_type, new_pin, new_pin_size,
930e8dbd92cSJens Wiklander 			      &session->token->db_main->so_pin_salt,
931e8dbd92cSJens Wiklander 			      session->token->db_main->so_pin_hash);
932e8dbd92cSJens Wiklander 		if (rc)
933e8dbd92cSJens Wiklander 			return rc;
934e8dbd92cSJens Wiklander 		session->token->db_main->so_pin_count = 0;
935e8dbd92cSJens Wiklander 		flags_clear = PKCS11_CKFT_SO_PIN_COUNT_LOW |
936e8dbd92cSJens Wiklander 			      PKCS11_CKFT_SO_PIN_FINAL_TRY |
937e8dbd92cSJens Wiklander 			      PKCS11_CKFT_SO_PIN_LOCKED |
938e8dbd92cSJens Wiklander 			      PKCS11_CKFT_SO_PIN_TO_BE_CHANGED;
939e8dbd92cSJens Wiklander 		break;
940e8dbd92cSJens Wiklander 	case PKCS11_CKU_USER:
941e8dbd92cSJens Wiklander 		rc = hash_pin(user_type, new_pin, new_pin_size,
942e8dbd92cSJens Wiklander 			      &session->token->db_main->user_pin_salt,
943e8dbd92cSJens Wiklander 			      session->token->db_main->user_pin_hash);
944e8dbd92cSJens Wiklander 		if (rc)
945e8dbd92cSJens Wiklander 			return rc;
946e8dbd92cSJens Wiklander 		session->token->db_main->user_pin_count = 0;
947e8dbd92cSJens Wiklander 		flags_clear = PKCS11_CKFT_USER_PIN_COUNT_LOW |
948e8dbd92cSJens Wiklander 			      PKCS11_CKFT_USER_PIN_FINAL_TRY |
949e8dbd92cSJens Wiklander 			      PKCS11_CKFT_USER_PIN_LOCKED |
950e8dbd92cSJens Wiklander 			      PKCS11_CKFT_USER_PIN_TO_BE_CHANGED;
951e8dbd92cSJens Wiklander 		flags_set = PKCS11_CKFT_USER_PIN_INITIALIZED;
952e8dbd92cSJens Wiklander 		break;
953e8dbd92cSJens Wiklander 	default:
954e8dbd92cSJens Wiklander 		return PKCS11_CKR_FUNCTION_FAILED;
955e8dbd92cSJens Wiklander 	}
956e8dbd92cSJens Wiklander 
957e8dbd92cSJens Wiklander 	session->token->db_main->flags &= ~flags_clear;
958e8dbd92cSJens Wiklander 	session->token->db_main->flags |= flags_set;
959e8dbd92cSJens Wiklander 
960e8dbd92cSJens Wiklander 	update_persistent_db(session->token);
961e8dbd92cSJens Wiklander 
962e8dbd92cSJens Wiklander 	return PKCS11_CKR_OK;
963e8dbd92cSJens Wiklander }
964e8dbd92cSJens Wiklander 
9654daf39b3SJens Wiklander enum pkcs11_rc entry_ck_init_pin(struct pkcs11_client *client,
966e8dbd92cSJens Wiklander 				 uint32_t ptypes, TEE_Param *params)
967e8dbd92cSJens Wiklander {
968e8dbd92cSJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
969e8dbd92cSJens Wiklander 						TEE_PARAM_TYPE_NONE,
970e8dbd92cSJens Wiklander 						TEE_PARAM_TYPE_NONE,
971e8dbd92cSJens Wiklander 						TEE_PARAM_TYPE_NONE);
972e8dbd92cSJens Wiklander 	struct pkcs11_session *session = NULL;
973e8dbd92cSJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
974e8dbd92cSJens Wiklander 	struct serialargs ctrlargs = { };
975e8dbd92cSJens Wiklander 	TEE_Param *ctrl = params;
976e8dbd92cSJens Wiklander 	uint32_t pin_size = 0;
977e8dbd92cSJens Wiklander 	void *pin = NULL;
978e8dbd92cSJens Wiklander 
979e8dbd92cSJens Wiklander 	if (!client || ptypes != exp_pt)
980e8dbd92cSJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
981e8dbd92cSJens Wiklander 
982e8dbd92cSJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
983e8dbd92cSJens Wiklander 
984f40f331fSEtienne Carriere 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
985e8dbd92cSJens Wiklander 	if (rc)
986e8dbd92cSJens Wiklander 		return rc;
987e8dbd92cSJens Wiklander 
988e8dbd92cSJens Wiklander 	rc = serialargs_get(&ctrlargs, &pin_size, sizeof(uint32_t));
989e8dbd92cSJens Wiklander 	if (rc)
990e8dbd92cSJens Wiklander 		return rc;
991e8dbd92cSJens Wiklander 
992e8dbd92cSJens Wiklander 	rc = serialargs_get_ptr(&ctrlargs, &pin, pin_size);
993e8dbd92cSJens Wiklander 	if (rc)
994e8dbd92cSJens Wiklander 		return rc;
995e8dbd92cSJens Wiklander 
996e8dbd92cSJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs))
997e8dbd92cSJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
998e8dbd92cSJens Wiklander 
999e8dbd92cSJens Wiklander 	if (!pkcs11_session_is_so(session))
1000e8dbd92cSJens Wiklander 		return PKCS11_CKR_USER_NOT_LOGGED_IN;
1001e8dbd92cSJens Wiklander 
1002e8dbd92cSJens Wiklander 	assert(session->token->db_main->flags & PKCS11_CKFT_TOKEN_INITIALIZED);
1003e8dbd92cSJens Wiklander 
1004f40f331fSEtienne Carriere 	IMSG("PKCS11 session %"PRIu32": init PIN", session->handle);
1005e8dbd92cSJens Wiklander 
1006e8dbd92cSJens Wiklander 	return set_pin(session, pin, pin_size, PKCS11_CKU_USER);
1007e8dbd92cSJens Wiklander }
10081dbb91e7SJens Wiklander 
10094daf39b3SJens Wiklander static enum pkcs11_rc check_so_pin(struct pkcs11_session *session,
10101dbb91e7SJens Wiklander 				   uint8_t *pin, size_t pin_size)
10111dbb91e7SJens Wiklander {
10121dbb91e7SJens Wiklander 	struct ck_token *token = session->token;
10131dbb91e7SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
10141dbb91e7SJens Wiklander 
10151dbb91e7SJens Wiklander 	assert(token->db_main->flags & PKCS11_CKFT_TOKEN_INITIALIZED);
10161dbb91e7SJens Wiklander 
10171dbb91e7SJens Wiklander 	if (token->db_main->flags & PKCS11_CKFT_SO_PIN_LOCKED)
10181dbb91e7SJens Wiklander 		return PKCS11_CKR_PIN_LOCKED;
10191dbb91e7SJens Wiklander 
10201dbb91e7SJens Wiklander 	rc = verify_pin(PKCS11_CKU_SO, pin, pin_size,
10211dbb91e7SJens Wiklander 			token->db_main->so_pin_salt,
10221dbb91e7SJens Wiklander 			token->db_main->so_pin_hash);
10231dbb91e7SJens Wiklander 	if (rc) {
10241dbb91e7SJens Wiklander 		unsigned int pin_count = 0;
10251dbb91e7SJens Wiklander 
10261dbb91e7SJens Wiklander 		if (rc != PKCS11_CKR_PIN_INCORRECT)
10271dbb91e7SJens Wiklander 			return rc;
10281dbb91e7SJens Wiklander 
10291dbb91e7SJens Wiklander 		token->db_main->flags |= PKCS11_CKFT_SO_PIN_COUNT_LOW;
10301dbb91e7SJens Wiklander 		token->db_main->so_pin_count++;
10311dbb91e7SJens Wiklander 
10321dbb91e7SJens Wiklander 		pin_count = token->db_main->so_pin_count;
10331dbb91e7SJens Wiklander 		if (pin_count == PKCS11_TOKEN_SO_PIN_COUNT_MAX - 1)
10341dbb91e7SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_SO_PIN_FINAL_TRY;
10351dbb91e7SJens Wiklander 		if (pin_count == PKCS11_TOKEN_SO_PIN_COUNT_MAX)
10361dbb91e7SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_SO_PIN_LOCKED;
10371dbb91e7SJens Wiklander 
10381dbb91e7SJens Wiklander 		update_persistent_db(token);
10391dbb91e7SJens Wiklander 
10401dbb91e7SJens Wiklander 		if (token->db_main->flags & PKCS11_CKFT_SO_PIN_LOCKED)
10411dbb91e7SJens Wiklander 			return PKCS11_CKR_PIN_LOCKED;
10421dbb91e7SJens Wiklander 
10431dbb91e7SJens Wiklander 		return PKCS11_CKR_PIN_INCORRECT;
10441dbb91e7SJens Wiklander 	}
10451dbb91e7SJens Wiklander 
10461dbb91e7SJens Wiklander 	if (token->db_main->so_pin_count) {
10471dbb91e7SJens Wiklander 		token->db_main->so_pin_count = 0;
10481dbb91e7SJens Wiklander 
10491dbb91e7SJens Wiklander 		update_persistent_db(token);
10501dbb91e7SJens Wiklander 	}
10511dbb91e7SJens Wiklander 
10521dbb91e7SJens Wiklander 	if (token->db_main->flags & (PKCS11_CKFT_SO_PIN_COUNT_LOW |
10531dbb91e7SJens Wiklander 				     PKCS11_CKFT_SO_PIN_FINAL_TRY)) {
10541dbb91e7SJens Wiklander 		token->db_main->flags &= ~(PKCS11_CKFT_SO_PIN_COUNT_LOW |
10551dbb91e7SJens Wiklander 					   PKCS11_CKFT_SO_PIN_FINAL_TRY);
10561dbb91e7SJens Wiklander 
10571dbb91e7SJens Wiklander 		update_persistent_db(token);
10581dbb91e7SJens Wiklander 	}
10591dbb91e7SJens Wiklander 
10601dbb91e7SJens Wiklander 	return PKCS11_CKR_OK;
10611dbb91e7SJens Wiklander }
10621dbb91e7SJens Wiklander 
10634daf39b3SJens Wiklander static enum pkcs11_rc check_user_pin(struct pkcs11_session *session,
10641dbb91e7SJens Wiklander 				     uint8_t *pin, size_t pin_size)
10651dbb91e7SJens Wiklander {
10661dbb91e7SJens Wiklander 	struct ck_token *token = session->token;
10671dbb91e7SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
10681dbb91e7SJens Wiklander 
10691dbb91e7SJens Wiklander 	if (!token->db_main->user_pin_salt)
10701dbb91e7SJens Wiklander 		return PKCS11_CKR_USER_PIN_NOT_INITIALIZED;
10711dbb91e7SJens Wiklander 
10721dbb91e7SJens Wiklander 	if (token->db_main->flags & PKCS11_CKFT_USER_PIN_LOCKED)
10731dbb91e7SJens Wiklander 		return PKCS11_CKR_PIN_LOCKED;
10741dbb91e7SJens Wiklander 
10751dbb91e7SJens Wiklander 	rc = verify_pin(PKCS11_CKU_USER, pin, pin_size,
10761dbb91e7SJens Wiklander 			token->db_main->user_pin_salt,
10771dbb91e7SJens Wiklander 			token->db_main->user_pin_hash);
10781dbb91e7SJens Wiklander 	if (rc) {
10791dbb91e7SJens Wiklander 		unsigned int pin_count = 0;
10801dbb91e7SJens Wiklander 
10811dbb91e7SJens Wiklander 		if (rc != PKCS11_CKR_PIN_INCORRECT)
10821dbb91e7SJens Wiklander 			return rc;
10831dbb91e7SJens Wiklander 
10841dbb91e7SJens Wiklander 		token->db_main->flags |= PKCS11_CKFT_USER_PIN_COUNT_LOW;
10851dbb91e7SJens Wiklander 		token->db_main->user_pin_count++;
10861dbb91e7SJens Wiklander 
10871dbb91e7SJens Wiklander 		pin_count = token->db_main->user_pin_count;
10881dbb91e7SJens Wiklander 		if (pin_count == PKCS11_TOKEN_USER_PIN_COUNT_MAX - 1)
10891dbb91e7SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_USER_PIN_FINAL_TRY;
10901dbb91e7SJens Wiklander 		if (pin_count == PKCS11_TOKEN_USER_PIN_COUNT_MAX)
10911dbb91e7SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_USER_PIN_LOCKED;
10921dbb91e7SJens Wiklander 
10931dbb91e7SJens Wiklander 		update_persistent_db(token);
10941dbb91e7SJens Wiklander 
10951dbb91e7SJens Wiklander 		if (token->db_main->flags & PKCS11_CKFT_USER_PIN_LOCKED)
10961dbb91e7SJens Wiklander 			return PKCS11_CKR_PIN_LOCKED;
10971dbb91e7SJens Wiklander 
10981dbb91e7SJens Wiklander 		return PKCS11_CKR_PIN_INCORRECT;
10991dbb91e7SJens Wiklander 	}
11001dbb91e7SJens Wiklander 
11011dbb91e7SJens Wiklander 	if (token->db_main->user_pin_count) {
11021dbb91e7SJens Wiklander 		token->db_main->user_pin_count = 0;
11031dbb91e7SJens Wiklander 
11041dbb91e7SJens Wiklander 		update_persistent_db(token);
11051dbb91e7SJens Wiklander 	}
11061dbb91e7SJens Wiklander 
11071dbb91e7SJens Wiklander 	if (token->db_main->flags & (PKCS11_CKFT_USER_PIN_COUNT_LOW |
11081dbb91e7SJens Wiklander 				     PKCS11_CKFT_USER_PIN_FINAL_TRY)) {
11091dbb91e7SJens Wiklander 		token->db_main->flags &= ~(PKCS11_CKFT_USER_PIN_COUNT_LOW |
11101dbb91e7SJens Wiklander 					   PKCS11_CKFT_USER_PIN_FINAL_TRY);
11111dbb91e7SJens Wiklander 
11121dbb91e7SJens Wiklander 		update_persistent_db(token);
11131dbb91e7SJens Wiklander 	}
11141dbb91e7SJens Wiklander 
11151dbb91e7SJens Wiklander 	return PKCS11_CKR_OK;
11161dbb91e7SJens Wiklander }
11171dbb91e7SJens Wiklander 
11184daf39b3SJens Wiklander enum pkcs11_rc entry_ck_set_pin(struct pkcs11_client *client,
11191dbb91e7SJens Wiklander 				uint32_t ptypes, TEE_Param *params)
11201dbb91e7SJens Wiklander {
11211dbb91e7SJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
11221dbb91e7SJens Wiklander 						TEE_PARAM_TYPE_NONE,
11231dbb91e7SJens Wiklander 						TEE_PARAM_TYPE_NONE,
11241dbb91e7SJens Wiklander 						TEE_PARAM_TYPE_NONE);
11251dbb91e7SJens Wiklander 	struct pkcs11_session *session = NULL;
11261dbb91e7SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
11271dbb91e7SJens Wiklander 	struct serialargs ctrlargs = { };
11281dbb91e7SJens Wiklander 	uint32_t old_pin_size = 0;
11291dbb91e7SJens Wiklander 	TEE_Param *ctrl = params;
11301dbb91e7SJens Wiklander 	uint32_t pin_size = 0;
11311dbb91e7SJens Wiklander 	void *old_pin = NULL;
11321dbb91e7SJens Wiklander 	void *pin = NULL;
11331dbb91e7SJens Wiklander 
11341dbb91e7SJens Wiklander 	if (!client || ptypes != exp_pt)
11351dbb91e7SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
11361dbb91e7SJens Wiklander 
11371dbb91e7SJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
11381dbb91e7SJens Wiklander 
1139f40f331fSEtienne Carriere 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
11401dbb91e7SJens Wiklander 	if (rc)
11411dbb91e7SJens Wiklander 		return rc;
11421dbb91e7SJens Wiklander 
11431dbb91e7SJens Wiklander 	rc = serialargs_get(&ctrlargs, &old_pin_size, sizeof(uint32_t));
11441dbb91e7SJens Wiklander 	if (rc)
11451dbb91e7SJens Wiklander 		return rc;
11461dbb91e7SJens Wiklander 
11471dbb91e7SJens Wiklander 	rc = serialargs_get(&ctrlargs, &pin_size, sizeof(uint32_t));
11481dbb91e7SJens Wiklander 	if (rc)
11491dbb91e7SJens Wiklander 		return rc;
11501dbb91e7SJens Wiklander 
11511dbb91e7SJens Wiklander 	rc = serialargs_get_ptr(&ctrlargs, &old_pin, old_pin_size);
11521dbb91e7SJens Wiklander 	if (rc)
11531dbb91e7SJens Wiklander 		return rc;
11541dbb91e7SJens Wiklander 
11551dbb91e7SJens Wiklander 	rc = serialargs_get_ptr(&ctrlargs, &pin, pin_size);
11561dbb91e7SJens Wiklander 	if (rc)
11571dbb91e7SJens Wiklander 		return rc;
11581dbb91e7SJens Wiklander 
11591dbb91e7SJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs))
11601dbb91e7SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
11611dbb91e7SJens Wiklander 
11621dbb91e7SJens Wiklander 	if (!pkcs11_session_is_read_write(session))
11631dbb91e7SJens Wiklander 		return PKCS11_CKR_SESSION_READ_ONLY;
11641dbb91e7SJens Wiklander 
11651dbb91e7SJens Wiklander 	if (pkcs11_session_is_so(session)) {
11661dbb91e7SJens Wiklander 		if (!(session->token->db_main->flags &
11671dbb91e7SJens Wiklander 		      PKCS11_CKFT_TOKEN_INITIALIZED))
11681dbb91e7SJens Wiklander 			return PKCS11_CKR_GENERAL_ERROR;
11691dbb91e7SJens Wiklander 
11701dbb91e7SJens Wiklander 		rc = check_so_pin(session, old_pin, old_pin_size);
11711dbb91e7SJens Wiklander 		if (rc)
11721dbb91e7SJens Wiklander 			return rc;
11731dbb91e7SJens Wiklander 
1174f40f331fSEtienne Carriere 		IMSG("PKCS11 session %"PRIu32": set PIN", session->handle);
11751dbb91e7SJens Wiklander 
11761dbb91e7SJens Wiklander 		return set_pin(session, pin, pin_size, PKCS11_CKU_SO);
11771dbb91e7SJens Wiklander 	}
11781dbb91e7SJens Wiklander 
11791dbb91e7SJens Wiklander 	if (!(session->token->db_main->flags &
11801dbb91e7SJens Wiklander 	      PKCS11_CKFT_USER_PIN_INITIALIZED))
11811dbb91e7SJens Wiklander 		return PKCS11_CKR_GENERAL_ERROR;
11821dbb91e7SJens Wiklander 
11831dbb91e7SJens Wiklander 	rc = check_user_pin(session, old_pin, old_pin_size);
11841dbb91e7SJens Wiklander 	if (rc)
11851dbb91e7SJens Wiklander 		return rc;
11861dbb91e7SJens Wiklander 
1187f40f331fSEtienne Carriere 	IMSG("PKCS11 session %"PRIu32": set PIN", session->handle);
11881dbb91e7SJens Wiklander 
11891dbb91e7SJens Wiklander 	return set_pin(session, pin, pin_size, PKCS11_CKU_USER);
11901dbb91e7SJens Wiklander }
1191f7cc36c0SJens Wiklander 
1192f7cc36c0SJens Wiklander static void session_login_user(struct pkcs11_session *session)
1193f7cc36c0SJens Wiklander {
1194f7cc36c0SJens Wiklander 	struct pkcs11_client *client = session->client;
1195f7cc36c0SJens Wiklander 	struct pkcs11_session *sess = NULL;
1196f7cc36c0SJens Wiklander 
1197f7cc36c0SJens Wiklander 	TAILQ_FOREACH(sess, &client->session_list, link) {
1198f7cc36c0SJens Wiklander 		if (sess->token != session->token)
1199f7cc36c0SJens Wiklander 			continue;
1200f7cc36c0SJens Wiklander 
1201f7cc36c0SJens Wiklander 		if (pkcs11_session_is_read_write(sess))
1202f7cc36c0SJens Wiklander 			sess->state = PKCS11_CKS_RW_USER_FUNCTIONS;
1203f7cc36c0SJens Wiklander 		else
1204f7cc36c0SJens Wiklander 			sess->state = PKCS11_CKS_RO_USER_FUNCTIONS;
1205f7cc36c0SJens Wiklander 	}
1206f7cc36c0SJens Wiklander }
1207f7cc36c0SJens Wiklander 
1208f7cc36c0SJens Wiklander static void session_login_so(struct pkcs11_session *session)
1209f7cc36c0SJens Wiklander {
1210f7cc36c0SJens Wiklander 	struct pkcs11_client *client = session->client;
1211f7cc36c0SJens Wiklander 	struct pkcs11_session *sess = NULL;
1212f7cc36c0SJens Wiklander 
1213f7cc36c0SJens Wiklander 	TAILQ_FOREACH(sess, &client->session_list, link) {
1214f7cc36c0SJens Wiklander 		if (sess->token != session->token)
1215f7cc36c0SJens Wiklander 			continue;
1216f7cc36c0SJens Wiklander 
1217f7cc36c0SJens Wiklander 		if (pkcs11_session_is_read_write(sess))
1218f7cc36c0SJens Wiklander 			sess->state = PKCS11_CKS_RW_SO_FUNCTIONS;
1219f7cc36c0SJens Wiklander 		else
1220f7cc36c0SJens Wiklander 			TEE_Panic(0);
1221f7cc36c0SJens Wiklander 	}
1222f7cc36c0SJens Wiklander }
1223f7cc36c0SJens Wiklander 
1224f7cc36c0SJens Wiklander static void session_logout(struct pkcs11_session *session)
1225f7cc36c0SJens Wiklander {
1226f7cc36c0SJens Wiklander 	struct pkcs11_client *client = session->client;
1227f7cc36c0SJens Wiklander 	struct pkcs11_session *sess = NULL;
1228f7cc36c0SJens Wiklander 
1229f7cc36c0SJens Wiklander 	TAILQ_FOREACH(sess, &client->session_list, link) {
1230f7cc36c0SJens Wiklander 		if (sess->token != session->token)
1231f7cc36c0SJens Wiklander 			continue;
1232f7cc36c0SJens Wiklander 
1233f7cc36c0SJens Wiklander 		if (pkcs11_session_is_read_write(sess))
1234f7cc36c0SJens Wiklander 			sess->state = PKCS11_CKS_RW_PUBLIC_SESSION;
1235f7cc36c0SJens Wiklander 		else
1236f7cc36c0SJens Wiklander 			sess->state = PKCS11_CKS_RO_PUBLIC_SESSION;
1237f7cc36c0SJens Wiklander 	}
1238f7cc36c0SJens Wiklander }
1239f7cc36c0SJens Wiklander 
12404daf39b3SJens Wiklander enum pkcs11_rc entry_ck_login(struct pkcs11_client *client,
1241f7cc36c0SJens Wiklander 			      uint32_t ptypes, TEE_Param *params)
1242f7cc36c0SJens Wiklander {
1243f7cc36c0SJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
1244f7cc36c0SJens Wiklander 						TEE_PARAM_TYPE_NONE,
1245f7cc36c0SJens Wiklander 						TEE_PARAM_TYPE_NONE,
1246f7cc36c0SJens Wiklander 						TEE_PARAM_TYPE_NONE);
1247f7cc36c0SJens Wiklander 	struct pkcs11_session *session = NULL;
1248f7cc36c0SJens Wiklander 	struct pkcs11_session *sess = NULL;
1249f7cc36c0SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
1250f7cc36c0SJens Wiklander 	struct serialargs ctrlargs = { };
1251f7cc36c0SJens Wiklander 	TEE_Param *ctrl = params;
1252f7cc36c0SJens Wiklander 	uint32_t user_type = 0;
1253f7cc36c0SJens Wiklander 	uint32_t pin_size = 0;
1254f7cc36c0SJens Wiklander 	void *pin = NULL;
1255f7cc36c0SJens Wiklander 
1256f7cc36c0SJens Wiklander 	if (!client || ptypes != exp_pt)
1257f7cc36c0SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
1258f7cc36c0SJens Wiklander 
1259f7cc36c0SJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
1260f7cc36c0SJens Wiklander 
1261f40f331fSEtienne Carriere 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
1262f7cc36c0SJens Wiklander 	if (rc)
1263f7cc36c0SJens Wiklander 		return rc;
1264f7cc36c0SJens Wiklander 
1265f7cc36c0SJens Wiklander 	rc = serialargs_get(&ctrlargs, &user_type, sizeof(uint32_t));
1266f7cc36c0SJens Wiklander 	if (rc)
1267f7cc36c0SJens Wiklander 		return rc;
1268f7cc36c0SJens Wiklander 
1269f7cc36c0SJens Wiklander 	rc = serialargs_get(&ctrlargs, &pin_size, sizeof(uint32_t));
1270f7cc36c0SJens Wiklander 	if (rc)
1271f7cc36c0SJens Wiklander 		return rc;
1272f7cc36c0SJens Wiklander 
1273f7cc36c0SJens Wiklander 	rc = serialargs_get_ptr(&ctrlargs, &pin, pin_size);
1274f7cc36c0SJens Wiklander 	if (rc)
1275f7cc36c0SJens Wiklander 		return rc;
1276f7cc36c0SJens Wiklander 
1277f7cc36c0SJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs))
1278f7cc36c0SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
1279f7cc36c0SJens Wiklander 
1280f7cc36c0SJens Wiklander 	switch (user_type) {
1281f7cc36c0SJens Wiklander 	case PKCS11_CKU_SO:
1282f7cc36c0SJens Wiklander 		if (pkcs11_session_is_so(session))
1283f7cc36c0SJens Wiklander 			return PKCS11_CKR_USER_ALREADY_LOGGED_IN;
1284f7cc36c0SJens Wiklander 
1285f7cc36c0SJens Wiklander 		if (pkcs11_session_is_user(session))
1286f7cc36c0SJens Wiklander 			return PKCS11_CKR_USER_ANOTHER_ALREADY_LOGGED_IN;
1287f7cc36c0SJens Wiklander 
1288f7cc36c0SJens Wiklander 		TAILQ_FOREACH(sess, &client->session_list, link)
1289f7cc36c0SJens Wiklander 			if (sess->token == session->token &&
1290f7cc36c0SJens Wiklander 			    !pkcs11_session_is_read_write(sess))
1291f7cc36c0SJens Wiklander 				return PKCS11_CKR_SESSION_READ_ONLY_EXISTS;
1292f7cc36c0SJens Wiklander 
1293f7cc36c0SJens Wiklander 		/*
1294f7cc36c0SJens Wiklander 		 * This is the point where we could check if another client
1295f7cc36c0SJens Wiklander 		 * has another user or SO logged in.
1296f7cc36c0SJens Wiklander 		 *
1297f7cc36c0SJens Wiklander 		 * The spec says:
1298f7cc36c0SJens Wiklander 		 * CKR_USER_TOO_MANY_TYPES: An attempt was made to have
1299f7cc36c0SJens Wiklander 		 * more distinct users simultaneously logged into the token
1300f7cc36c0SJens Wiklander 		 * than the token and/or library permits. For example, if
1301f7cc36c0SJens Wiklander 		 * some application has an open SO session, and another
1302f7cc36c0SJens Wiklander 		 * application attempts to log the normal user into a
1303f7cc36c0SJens Wiklander 		 * session, the attempt may return this error. It is not
1304f7cc36c0SJens Wiklander 		 * required to, however. Only if the simultaneous distinct
1305f7cc36c0SJens Wiklander 		 * users cannot be supported does C_Login have to return
1306f7cc36c0SJens Wiklander 		 * this value. Note that this error code generalizes to
1307f7cc36c0SJens Wiklander 		 * true multi-user tokens.
1308f7cc36c0SJens Wiklander 		 *
1309f7cc36c0SJens Wiklander 		 * So it's permitted to have another user or SO logged in
1310f7cc36c0SJens Wiklander 		 * from another client.
1311f7cc36c0SJens Wiklander 		 */
1312f7cc36c0SJens Wiklander 
1313f7cc36c0SJens Wiklander 		rc = check_so_pin(session, pin, pin_size);
1314f7cc36c0SJens Wiklander 		if (!rc)
1315f7cc36c0SJens Wiklander 			session_login_so(session);
1316f7cc36c0SJens Wiklander 
1317f7cc36c0SJens Wiklander 		break;
1318f7cc36c0SJens Wiklander 
1319f7cc36c0SJens Wiklander 	case PKCS11_CKU_USER:
1320f7cc36c0SJens Wiklander 		if (pkcs11_session_is_so(session))
1321f7cc36c0SJens Wiklander 			return PKCS11_CKR_USER_ANOTHER_ALREADY_LOGGED_IN;
1322f7cc36c0SJens Wiklander 
1323f7cc36c0SJens Wiklander 		if (pkcs11_session_is_user(session))
1324f7cc36c0SJens Wiklander 			return PKCS11_CKR_USER_ALREADY_LOGGED_IN;
1325f7cc36c0SJens Wiklander 
1326f7cc36c0SJens Wiklander 		/*
1327f7cc36c0SJens Wiklander 		 * This is the point where we could check if another client
1328f7cc36c0SJens Wiklander 		 * has another user or SO logged in.
1329f7cc36c0SJens Wiklander 		 * See comment on CKR_USER_TOO_MANY_TYPES above.
1330f7cc36c0SJens Wiklander 		 */
1331f7cc36c0SJens Wiklander 
1332f7cc36c0SJens Wiklander 		rc = check_user_pin(session, pin, pin_size);
1333f7cc36c0SJens Wiklander 		if (!rc)
1334f7cc36c0SJens Wiklander 			session_login_user(session);
1335f7cc36c0SJens Wiklander 
1336f7cc36c0SJens Wiklander 		break;
1337f7cc36c0SJens Wiklander 
1338f7cc36c0SJens Wiklander 	case PKCS11_CKU_CONTEXT_SPECIFIC:
1339f7cc36c0SJens Wiklander 		return PKCS11_CKR_OPERATION_NOT_INITIALIZED;
1340f7cc36c0SJens Wiklander 
1341f7cc36c0SJens Wiklander 	default:
1342f7cc36c0SJens Wiklander 		return PKCS11_CKR_USER_TYPE_INVALID;
1343f7cc36c0SJens Wiklander 	}
1344f7cc36c0SJens Wiklander 
1345f7cc36c0SJens Wiklander 	if (!rc)
1346f40f331fSEtienne Carriere 		IMSG("PKCS11 session %"PRIu32": login", session->handle);
1347f7cc36c0SJens Wiklander 
1348f7cc36c0SJens Wiklander 	return rc;
1349f7cc36c0SJens Wiklander }
1350f7cc36c0SJens Wiklander 
13514daf39b3SJens Wiklander enum pkcs11_rc entry_ck_logout(struct pkcs11_client *client,
1352f7cc36c0SJens Wiklander 			       uint32_t ptypes, TEE_Param *params)
1353f7cc36c0SJens Wiklander {
1354f7cc36c0SJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
1355f7cc36c0SJens Wiklander 						TEE_PARAM_TYPE_NONE,
1356f7cc36c0SJens Wiklander 						TEE_PARAM_TYPE_NONE,
1357f7cc36c0SJens Wiklander 						TEE_PARAM_TYPE_NONE);
1358f7cc36c0SJens Wiklander 	struct pkcs11_session *session = NULL;
1359f7cc36c0SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
1360f7cc36c0SJens Wiklander 	struct serialargs ctrlargs = { };
1361f7cc36c0SJens Wiklander 	TEE_Param *ctrl = params;
1362f7cc36c0SJens Wiklander 
1363f7cc36c0SJens Wiklander 	if (!client || ptypes != exp_pt)
1364f7cc36c0SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
1365f7cc36c0SJens Wiklander 
1366f7cc36c0SJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
1367f7cc36c0SJens Wiklander 
1368f40f331fSEtienne Carriere 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
1369f7cc36c0SJens Wiklander 	if (rc)
1370f7cc36c0SJens Wiklander 		return rc;
1371f7cc36c0SJens Wiklander 
1372f7cc36c0SJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs))
1373f7cc36c0SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
1374f7cc36c0SJens Wiklander 
1375f7cc36c0SJens Wiklander 	if (pkcs11_session_is_public(session))
1376f7cc36c0SJens Wiklander 		return PKCS11_CKR_USER_NOT_LOGGED_IN;
1377f7cc36c0SJens Wiklander 
1378f7cc36c0SJens Wiklander 	session_logout(session);
1379f7cc36c0SJens Wiklander 
1380f40f331fSEtienne Carriere 	IMSG("PKCS11 session %"PRIu32": logout", session->handle);
1381f7cc36c0SJens Wiklander 
1382f7cc36c0SJens Wiklander 	return PKCS11_CKR_OK;
1383f7cc36c0SJens Wiklander }
1384