xref: /optee_os/ta/pkcs11/src/pkcs11_token.c (revision 920e0127462ae452d2bd21c25e6c81a699dc38d8)
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>
71a27b197SVesa Jääskeläinen #include <config.h>
8d38f9635SEtienne Carriere #include <confine_array_index.h>
9c84ccd0aSEtienne Carriere #include <pkcs11_ta.h>
10d628ebd9SEtienne Carriere #include <printk.h>
1122587dc4SVesa Jääskeläinen #include <pta_system.h>
12c84ccd0aSEtienne Carriere #include <string.h>
13c84ccd0aSEtienne Carriere #include <string_ext.h>
14c84ccd0aSEtienne Carriere #include <sys/queue.h>
15c84ccd0aSEtienne Carriere #include <tee_api_types.h>
16c84ccd0aSEtienne Carriere #include <tee_internal_api_extensions.h>
17c84ccd0aSEtienne Carriere #include <util.h>
18c84ccd0aSEtienne Carriere 
19512cbf1dSJens Wiklander #include "attributes.h"
2049443fc0SEtienne Carriere #include "handle.h"
21c84ccd0aSEtienne Carriere #include "pkcs11_helpers.h"
22ee49d9f2SEtienne Carriere #include "pkcs11_token.h"
2355e6965cSEtienne Carriere #include "processing.h"
2422ac6984SEtienne Carriere #include "serializer.h"
2549443fc0SEtienne Carriere #include "token_capabilities.h"
26c84ccd0aSEtienne Carriere 
27edce8377SEtienne Carriere /* Number of tokens implemented by the TA. Token ID is the token index */
28c84ccd0aSEtienne Carriere #define TOKEN_COUNT		CFG_PKCS11_TA_TOKEN_COUNT
29c84ccd0aSEtienne Carriere 
3022587dc4SVesa Jääskeläinen /* RNG chunk size used to split RNG generation to smaller sizes */
3122587dc4SVesa Jääskeläinen #define RNG_CHUNK_SIZE		512U
3222587dc4SVesa Jääskeläinen 
33e084583eSEtienne Carriere /*
34e084583eSEtienne Carriere  * Structure tracking client applications
35e084583eSEtienne Carriere  *
36e084583eSEtienne Carriere  * @link - chained list of registered client applications
37e084583eSEtienne Carriere  * @sessions - list of the PKCS11 sessions opened by the client application
38bc555ee0SVesa Jääskeläinen  * @object_handle_db - Database for object handles in name space of client
39e084583eSEtienne Carriere  */
40e084583eSEtienne Carriere struct pkcs11_client {
41e084583eSEtienne Carriere 	TAILQ_ENTRY(pkcs11_client) link;
42e084583eSEtienne Carriere 	struct session_list session_list;
43e084583eSEtienne Carriere 	struct handle_db session_handle_db;
44bc555ee0SVesa Jääskeläinen 	struct handle_db object_handle_db;
45e084583eSEtienne Carriere };
46e084583eSEtienne Carriere 
47c84ccd0aSEtienne Carriere /* Static allocation of tokens runtime instances (reset to 0 at load) */
48c84ccd0aSEtienne Carriere struct ck_token ck_token[TOKEN_COUNT];
49c84ccd0aSEtienne Carriere 
50e084583eSEtienne Carriere static struct client_list pkcs11_client_list =
51e084583eSEtienne Carriere 	TAILQ_HEAD_INITIALIZER(pkcs11_client_list);
52e084583eSEtienne Carriere 
536e4f8f17SEtienne Carriere static void close_ck_session(struct pkcs11_session *session);
546e4f8f17SEtienne Carriere 
55c84ccd0aSEtienne Carriere struct ck_token *get_token(unsigned int token_id)
56c84ccd0aSEtienne Carriere {
57d38f9635SEtienne Carriere 	if (token_id < TOKEN_COUNT)
58d38f9635SEtienne Carriere 		return &ck_token[confine_array_index(token_id, TOKEN_COUNT)];
59c84ccd0aSEtienne Carriere 
60d38f9635SEtienne Carriere 	return NULL;
61c84ccd0aSEtienne Carriere }
62c84ccd0aSEtienne Carriere 
63c84ccd0aSEtienne Carriere unsigned int get_token_id(struct ck_token *token)
64c84ccd0aSEtienne Carriere {
65c84ccd0aSEtienne Carriere 	ptrdiff_t id = token - ck_token;
66c84ccd0aSEtienne Carriere 
67c84ccd0aSEtienne Carriere 	assert(id >= 0 && id < TOKEN_COUNT);
68c84ccd0aSEtienne Carriere 	return id;
69c84ccd0aSEtienne Carriere }
70c84ccd0aSEtienne Carriere 
71bc555ee0SVesa Jääskeläinen struct handle_db *get_object_handle_db(struct pkcs11_session *session)
72bc555ee0SVesa Jääskeläinen {
73bc555ee0SVesa Jääskeläinen 	return &session->client->object_handle_db;
74bc555ee0SVesa Jääskeläinen }
75bc555ee0SVesa Jääskeläinen 
76bc555ee0SVesa Jääskeläinen struct session_list *get_session_list(struct pkcs11_session *session)
77bc555ee0SVesa Jääskeläinen {
78bc555ee0SVesa Jääskeläinen 	return &session->client->session_list;
79bc555ee0SVesa Jääskeläinen }
80bc555ee0SVesa Jääskeläinen 
81e084583eSEtienne Carriere struct pkcs11_client *tee_session2client(void *tee_session)
82e084583eSEtienne Carriere {
83e084583eSEtienne Carriere 	struct pkcs11_client *client = NULL;
84e084583eSEtienne Carriere 
85e084583eSEtienne Carriere 	TAILQ_FOREACH(client, &pkcs11_client_list, link)
86e084583eSEtienne Carriere 		if (client == tee_session)
87e084583eSEtienne Carriere 			break;
88e084583eSEtienne Carriere 
89e084583eSEtienne Carriere 	return client;
90e084583eSEtienne Carriere }
91e084583eSEtienne Carriere 
926e4f8f17SEtienne Carriere struct pkcs11_session *pkcs11_handle2session(uint32_t handle,
936e4f8f17SEtienne Carriere 					     struct pkcs11_client *client)
946e4f8f17SEtienne Carriere {
956e4f8f17SEtienne Carriere 	return handle_lookup(&client->session_handle_db, handle);
966e4f8f17SEtienne Carriere }
976e4f8f17SEtienne Carriere 
98e084583eSEtienne Carriere struct pkcs11_client *register_client(void)
99e084583eSEtienne Carriere {
100e084583eSEtienne Carriere 	struct pkcs11_client *client = NULL;
101e084583eSEtienne Carriere 
102e084583eSEtienne Carriere 	client = TEE_Malloc(sizeof(*client), TEE_MALLOC_FILL_ZERO);
103e084583eSEtienne Carriere 	if (!client)
104e084583eSEtienne Carriere 		return NULL;
105e084583eSEtienne Carriere 
106e084583eSEtienne Carriere 	TAILQ_INSERT_HEAD(&pkcs11_client_list, client, link);
107e084583eSEtienne Carriere 	TAILQ_INIT(&client->session_list);
108e084583eSEtienne Carriere 	handle_db_init(&client->session_handle_db);
109bc555ee0SVesa Jääskeläinen 	handle_db_init(&client->object_handle_db);
110e084583eSEtienne Carriere 
111e084583eSEtienne Carriere 	return client;
112e084583eSEtienne Carriere }
113e084583eSEtienne Carriere 
114e084583eSEtienne Carriere void unregister_client(struct pkcs11_client *client)
115e084583eSEtienne Carriere {
1166e4f8f17SEtienne Carriere 	struct pkcs11_session *session = NULL;
1176e4f8f17SEtienne Carriere 	struct pkcs11_session *next = NULL;
1186e4f8f17SEtienne Carriere 
119e084583eSEtienne Carriere 	if (!client) {
120e084583eSEtienne Carriere 		EMSG("Invalid TEE session handle");
121e084583eSEtienne Carriere 		return;
122e084583eSEtienne Carriere 	}
123e084583eSEtienne Carriere 
1246e4f8f17SEtienne Carriere 	TAILQ_FOREACH_SAFE(session, &client->session_list, link, next)
1256e4f8f17SEtienne Carriere 		close_ck_session(session);
1266e4f8f17SEtienne Carriere 
127e084583eSEtienne Carriere 	TAILQ_REMOVE(&pkcs11_client_list, client, link);
128bc555ee0SVesa Jääskeläinen 	handle_db_destroy(&client->object_handle_db);
129e084583eSEtienne Carriere 	handle_db_destroy(&client->session_handle_db);
130e084583eSEtienne Carriere 	TEE_Free(client);
131e084583eSEtienne Carriere }
132e084583eSEtienne Carriere 
133c84ccd0aSEtienne Carriere static TEE_Result pkcs11_token_init(unsigned int id)
134c84ccd0aSEtienne Carriere {
135c84ccd0aSEtienne Carriere 	struct ck_token *token = init_persistent_db(id);
136c84ccd0aSEtienne Carriere 
137c84ccd0aSEtienne Carriere 	if (!token)
138c84ccd0aSEtienne Carriere 		return TEE_ERROR_SECURITY;
139c84ccd0aSEtienne Carriere 
140c84ccd0aSEtienne Carriere 	if (token->state == PKCS11_TOKEN_RESET) {
141c84ccd0aSEtienne Carriere 		/* As per PKCS#11 spec, token resets to read/write state */
142c84ccd0aSEtienne Carriere 		token->state = PKCS11_TOKEN_READ_WRITE;
143c84ccd0aSEtienne Carriere 		token->session_count = 0;
144c84ccd0aSEtienne Carriere 		token->rw_session_count = 0;
145c84ccd0aSEtienne Carriere 	}
146c84ccd0aSEtienne Carriere 
147c84ccd0aSEtienne Carriere 	return TEE_SUCCESS;
148c84ccd0aSEtienne Carriere }
149c84ccd0aSEtienne Carriere 
150c84ccd0aSEtienne Carriere TEE_Result pkcs11_init(void)
151c84ccd0aSEtienne Carriere {
152c84ccd0aSEtienne Carriere 	unsigned int id = 0;
153c84ccd0aSEtienne Carriere 	TEE_Result ret = TEE_ERROR_GENERIC;
154c84ccd0aSEtienne Carriere 
155c84ccd0aSEtienne Carriere 	for (id = 0; id < TOKEN_COUNT; id++) {
156c84ccd0aSEtienne Carriere 		ret = pkcs11_token_init(id);
157c84ccd0aSEtienne Carriere 		if (ret)
158e084583eSEtienne Carriere 			break;
159c84ccd0aSEtienne Carriere 	}
160c84ccd0aSEtienne Carriere 
161c84ccd0aSEtienne Carriere 	return ret;
162c84ccd0aSEtienne Carriere }
163c84ccd0aSEtienne Carriere 
164c84ccd0aSEtienne Carriere void pkcs11_deinit(void)
165c84ccd0aSEtienne Carriere {
166c84ccd0aSEtienne Carriere 	unsigned int id = 0;
167c84ccd0aSEtienne Carriere 
168c84ccd0aSEtienne Carriere 	for (id = 0; id < TOKEN_COUNT; id++)
169c84ccd0aSEtienne Carriere 		close_persistent_db(get_token(id));
170c84ccd0aSEtienne Carriere }
17122ac6984SEtienne Carriere 
172512cbf1dSJens Wiklander /*
173512cbf1dSJens Wiklander  * Currently no support for dual operations.
174512cbf1dSJens Wiklander  */
175512cbf1dSJens Wiklander enum pkcs11_rc set_processing_state(struct pkcs11_session *session,
176512cbf1dSJens Wiklander 				    enum processing_func function,
177512cbf1dSJens Wiklander 				    struct pkcs11_object *obj1,
178512cbf1dSJens Wiklander 				    struct pkcs11_object *obj2)
179512cbf1dSJens Wiklander {
180512cbf1dSJens Wiklander 	enum pkcs11_proc_state state = PKCS11_SESSION_READY;
181512cbf1dSJens Wiklander 	struct active_processing *proc = NULL;
182512cbf1dSJens Wiklander 
183512cbf1dSJens Wiklander 	if (session->processing)
184512cbf1dSJens Wiklander 		return PKCS11_CKR_OPERATION_ACTIVE;
185512cbf1dSJens Wiklander 
186512cbf1dSJens Wiklander 	switch (function) {
187512cbf1dSJens Wiklander 	case PKCS11_FUNCTION_ENCRYPT:
188512cbf1dSJens Wiklander 		state = PKCS11_SESSION_ENCRYPTING;
189512cbf1dSJens Wiklander 		break;
190512cbf1dSJens Wiklander 	case PKCS11_FUNCTION_DECRYPT:
191512cbf1dSJens Wiklander 		state = PKCS11_SESSION_DECRYPTING;
192512cbf1dSJens Wiklander 		break;
193512cbf1dSJens Wiklander 	case PKCS11_FUNCTION_SIGN:
194512cbf1dSJens Wiklander 		state = PKCS11_SESSION_SIGNING;
195512cbf1dSJens Wiklander 		break;
196512cbf1dSJens Wiklander 	case PKCS11_FUNCTION_VERIFY:
197512cbf1dSJens Wiklander 		state = PKCS11_SESSION_VERIFYING;
198512cbf1dSJens Wiklander 		break;
199512cbf1dSJens Wiklander 	case PKCS11_FUNCTION_DIGEST:
200512cbf1dSJens Wiklander 		state = PKCS11_SESSION_DIGESTING;
201512cbf1dSJens Wiklander 		break;
202512cbf1dSJens Wiklander 	case PKCS11_FUNCTION_DERIVE:
2035f80f270SRuchika Gupta 	case PKCS11_FUNCTION_WRAP:
2045f80f270SRuchika Gupta 	case PKCS11_FUNCTION_UNWRAP:
2055f80f270SRuchika Gupta 		state = PKCS11_SESSION_BUSY;
206512cbf1dSJens Wiklander 		break;
207512cbf1dSJens Wiklander 	default:
208512cbf1dSJens Wiklander 		TEE_Panic(function);
209512cbf1dSJens Wiklander 		return -1;
210512cbf1dSJens Wiklander 	}
211512cbf1dSJens Wiklander 
212512cbf1dSJens Wiklander 	proc = TEE_Malloc(sizeof(*proc), TEE_MALLOC_FILL_ZERO);
213512cbf1dSJens Wiklander 	if (!proc)
214512cbf1dSJens Wiklander 		return PKCS11_CKR_DEVICE_MEMORY;
215512cbf1dSJens Wiklander 
216512cbf1dSJens Wiklander 	/* Boolean are default to false and pointers to NULL */
217512cbf1dSJens Wiklander 	proc->state = state;
2182364aa69SRuchika Gupta 	proc->step = PKCS11_FUNC_STEP_INIT;
219512cbf1dSJens Wiklander 	proc->tee_op_handle = TEE_HANDLE_NULL;
220fb279d8bSVesa Jääskeläinen 	proc->tee_hash_algo = 0;
221fb279d8bSVesa Jääskeläinen 	proc->tee_hash_op_handle = TEE_HANDLE_NULL;
222512cbf1dSJens Wiklander 
223512cbf1dSJens Wiklander 	if (obj1 && get_bool(obj1->attributes, PKCS11_CKA_ALWAYS_AUTHENTICATE))
224512cbf1dSJens Wiklander 		proc->always_authen = true;
225512cbf1dSJens Wiklander 
226512cbf1dSJens Wiklander 	if (obj2 && get_bool(obj2->attributes, PKCS11_CKA_ALWAYS_AUTHENTICATE))
227512cbf1dSJens Wiklander 		proc->always_authen = true;
228512cbf1dSJens Wiklander 
229512cbf1dSJens Wiklander 	session->processing = proc;
230512cbf1dSJens Wiklander 
231512cbf1dSJens Wiklander 	return PKCS11_CKR_OK;
232512cbf1dSJens Wiklander }
233512cbf1dSJens Wiklander 
2344daf39b3SJens Wiklander enum pkcs11_rc entry_ck_slot_list(uint32_t ptypes, TEE_Param *params)
23522ac6984SEtienne Carriere {
23622ac6984SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
23722ac6984SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
23822ac6984SEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
23922ac6984SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
24039b43b78SJens Wiklander 	TEE_Param *out = params + 2;
24122ac6984SEtienne Carriere 	uint32_t token_id = 0;
24222ac6984SEtienne Carriere 	const size_t out_size = sizeof(token_id) * TOKEN_COUNT;
24322ac6984SEtienne Carriere 	uint8_t *id = NULL;
24422ac6984SEtienne Carriere 
24522ac6984SEtienne Carriere 	if (ptypes != exp_pt ||
24622ac6984SEtienne Carriere 	    params[0].memref.size != TEE_PARAM0_SIZE_MIN)
24722ac6984SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
24822ac6984SEtienne Carriere 
24922ac6984SEtienne Carriere 	if (out->memref.size < out_size) {
25022ac6984SEtienne Carriere 		out->memref.size = out_size;
25122ac6984SEtienne Carriere 
25222ac6984SEtienne Carriere 		if (out->memref.buffer)
25322ac6984SEtienne Carriere 			return PKCS11_CKR_BUFFER_TOO_SMALL;
25422ac6984SEtienne Carriere 		else
25522ac6984SEtienne Carriere 			return PKCS11_CKR_OK;
25622ac6984SEtienne Carriere 	}
25722ac6984SEtienne Carriere 
25822ac6984SEtienne Carriere 	for (token_id = 0, id = out->memref.buffer; token_id < TOKEN_COUNT;
25922ac6984SEtienne Carriere 	     token_id++, id += sizeof(token_id))
26022ac6984SEtienne Carriere 		TEE_MemMove(id, &token_id, sizeof(token_id));
26122ac6984SEtienne Carriere 
26222ac6984SEtienne Carriere 	out->memref.size = out_size;
26322ac6984SEtienne Carriere 
26422ac6984SEtienne Carriere 	return PKCS11_CKR_OK;
26522ac6984SEtienne Carriere }
266ce94efefSEtienne Carriere 
267b3ac5035SEtienne Carriere static void pad_str(uint8_t *str, size_t size)
268b3ac5035SEtienne Carriere {
269b3ac5035SEtienne Carriere 	int n = strnlen((char *)str, size);
270b3ac5035SEtienne Carriere 
271b3ac5035SEtienne Carriere 	TEE_MemFill(str + n, ' ', size - n);
272b3ac5035SEtienne Carriere }
273b3ac5035SEtienne Carriere 
274d628ebd9SEtienne Carriere static void set_token_description(struct pkcs11_slot_info *info)
275d628ebd9SEtienne Carriere {
276d628ebd9SEtienne Carriere 	char desc[sizeof(info->slot_description) + 1] = { 0 };
277d628ebd9SEtienne Carriere 	TEE_UUID dev_id = { };
278d628ebd9SEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
279d628ebd9SEtienne Carriere 	int n = 0;
280d628ebd9SEtienne Carriere 
281d628ebd9SEtienne Carriere 	res = TEE_GetPropertyAsUUID(TEE_PROPSET_TEE_IMPLEMENTATION,
282d628ebd9SEtienne Carriere 				    "gpd.tee.deviceID", &dev_id);
283d628ebd9SEtienne Carriere 	if (res == TEE_SUCCESS) {
284d628ebd9SEtienne Carriere 		n = snprintk(desc, sizeof(desc), PKCS11_SLOT_DESCRIPTION
285d628ebd9SEtienne Carriere 			     " - TEE UUID %pUl", (void *)&dev_id);
286d628ebd9SEtienne Carriere 	} else {
287d628ebd9SEtienne Carriere 		n = snprintf(desc, sizeof(desc), PKCS11_SLOT_DESCRIPTION
288d628ebd9SEtienne Carriere 			     " - No TEE UUID");
289d628ebd9SEtienne Carriere 	}
290d628ebd9SEtienne Carriere 	if (n < 0 || n >= (int)sizeof(desc))
291d628ebd9SEtienne Carriere 		TEE_Panic(0);
292d628ebd9SEtienne Carriere 
293d628ebd9SEtienne Carriere 	TEE_MemMove(info->slot_description, desc, n);
294d628ebd9SEtienne Carriere 	pad_str(info->slot_description, sizeof(info->slot_description));
295d628ebd9SEtienne Carriere }
296d628ebd9SEtienne Carriere 
2974daf39b3SJens Wiklander enum pkcs11_rc entry_ck_slot_info(uint32_t ptypes, TEE_Param *params)
298ce94efefSEtienne Carriere {
299ce94efefSEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
300ce94efefSEtienne Carriere 						TEE_PARAM_TYPE_NONE,
301ce94efefSEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
302ce94efefSEtienne Carriere 						TEE_PARAM_TYPE_NONE);
30339b43b78SJens Wiklander 	TEE_Param *ctrl = params;
30439b43b78SJens Wiklander 	TEE_Param *out = params + 2;
3054daf39b3SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
306ce94efefSEtienne Carriere 	struct serialargs ctrlargs = { };
307ce94efefSEtienne Carriere 	uint32_t token_id = 0;
308ce94efefSEtienne Carriere 	struct pkcs11_slot_info info = {
309ce94efefSEtienne Carriere 		.slot_description = PKCS11_SLOT_DESCRIPTION,
310ce94efefSEtienne Carriere 		.manufacturer_id = PKCS11_SLOT_MANUFACTURER,
311ce94efefSEtienne Carriere 		.flags = PKCS11_CKFS_TOKEN_PRESENT,
312ce94efefSEtienne Carriere 		.hardware_version = PKCS11_SLOT_HW_VERSION,
313ce94efefSEtienne Carriere 		.firmware_version = PKCS11_SLOT_FW_VERSION,
314ce94efefSEtienne Carriere 	};
315ce94efefSEtienne Carriere 
316ce94efefSEtienne Carriere 	COMPILE_TIME_ASSERT(sizeof(PKCS11_SLOT_DESCRIPTION) <=
317ce94efefSEtienne Carriere 			    sizeof(info.slot_description));
318ce94efefSEtienne Carriere 	COMPILE_TIME_ASSERT(sizeof(PKCS11_SLOT_MANUFACTURER) <=
319ce94efefSEtienne Carriere 			    sizeof(info.manufacturer_id));
320ce94efefSEtienne Carriere 
321ce94efefSEtienne Carriere 	if (ptypes != exp_pt || out->memref.size != sizeof(info))
322ce94efefSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
323ce94efefSEtienne Carriere 
324ce94efefSEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
325ce94efefSEtienne Carriere 
3264daf39b3SJens Wiklander 	rc = serialargs_get(&ctrlargs, &token_id, sizeof(token_id));
3274daf39b3SJens Wiklander 	if (rc)
3284daf39b3SJens Wiklander 		return rc;
329ce94efefSEtienne Carriere 
330ce94efefSEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
331ce94efefSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
332ce94efefSEtienne Carriere 
33329b0949aSEtienne Carriere 	if (!get_token(token_id))
334ce94efefSEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
335ce94efefSEtienne Carriere 
336d628ebd9SEtienne Carriere 	set_token_description(&info);
337d628ebd9SEtienne Carriere 
338b3ac5035SEtienne Carriere 	pad_str(info.manufacturer_id, sizeof(info.manufacturer_id));
339ce94efefSEtienne Carriere 
340ce94efefSEtienne Carriere 	out->memref.size = sizeof(info);
341ce94efefSEtienne Carriere 	TEE_MemMove(out->memref.buffer, &info, out->memref.size);
342ce94efefSEtienne Carriere 
343ce94efefSEtienne Carriere 	return PKCS11_CKR_OK;
344ce94efefSEtienne Carriere }
345030e7392SEtienne Carriere 
3464daf39b3SJens Wiklander enum pkcs11_rc entry_ck_token_info(uint32_t ptypes, TEE_Param *params)
347030e7392SEtienne Carriere {
348030e7392SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
349030e7392SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
350030e7392SEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
351030e7392SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
35239b43b78SJens Wiklander 	TEE_Param *ctrl = params;
35339b43b78SJens Wiklander 	TEE_Param *out = params + 2;
3544daf39b3SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
355030e7392SEtienne Carriere 	struct serialargs ctrlargs = { };
356030e7392SEtienne Carriere 	uint32_t token_id = 0;
357030e7392SEtienne Carriere 	struct ck_token *token = NULL;
358030e7392SEtienne Carriere 	struct pkcs11_token_info info = {
359030e7392SEtienne Carriere 		.manufacturer_id = PKCS11_TOKEN_MANUFACTURER,
360030e7392SEtienne Carriere 		.model = PKCS11_TOKEN_MODEL,
361030e7392SEtienne Carriere 		.max_session_count = UINT32_MAX,
362030e7392SEtienne Carriere 		.max_rw_session_count = UINT32_MAX,
363030e7392SEtienne Carriere 		.max_pin_len = PKCS11_TOKEN_PIN_SIZE_MAX,
364030e7392SEtienne Carriere 		.min_pin_len = PKCS11_TOKEN_PIN_SIZE_MIN,
365030e7392SEtienne Carriere 		.total_public_memory = UINT32_MAX,
366030e7392SEtienne Carriere 		.free_public_memory = UINT32_MAX,
367030e7392SEtienne Carriere 		.total_private_memory = UINT32_MAX,
368030e7392SEtienne Carriere 		.free_private_memory = UINT32_MAX,
369030e7392SEtienne Carriere 		.hardware_version = PKCS11_TOKEN_HW_VERSION,
370030e7392SEtienne Carriere 		.firmware_version = PKCS11_TOKEN_FW_VERSION,
371030e7392SEtienne Carriere 	};
37202b4d42aSEtienne Carriere 	char sn[sizeof(info.serial_number) + 1] = { 0 };
37302b4d42aSEtienne Carriere 	int n = 0;
374030e7392SEtienne Carriere 
375030e7392SEtienne Carriere 	if (ptypes != exp_pt || out->memref.size != sizeof(info))
376030e7392SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
377030e7392SEtienne Carriere 
378030e7392SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
379030e7392SEtienne Carriere 
3804daf39b3SJens Wiklander 	rc = serialargs_get(&ctrlargs, &token_id, sizeof(token_id));
3814daf39b3SJens Wiklander 	if (rc)
3824daf39b3SJens Wiklander 		return rc;
383030e7392SEtienne Carriere 
384030e7392SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
385030e7392SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
386030e7392SEtienne Carriere 
387030e7392SEtienne Carriere 	token = get_token(token_id);
388030e7392SEtienne Carriere 	if (!token)
389030e7392SEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
390030e7392SEtienne Carriere 
391030e7392SEtienne Carriere 	pad_str(info.manufacturer_id, sizeof(info.manufacturer_id));
392030e7392SEtienne Carriere 	pad_str(info.model, sizeof(info.model));
39302b4d42aSEtienne Carriere 
39402b4d42aSEtienne Carriere 	n = snprintf(sn, sizeof(sn), "%0*"PRIu32,
39502b4d42aSEtienne Carriere 		     (int)sizeof(info.serial_number), token_id);
39602b4d42aSEtienne Carriere 	if (n != (int)sizeof(info.serial_number))
39702b4d42aSEtienne Carriere 		TEE_Panic(0);
39802b4d42aSEtienne Carriere 
39902b4d42aSEtienne Carriere 	TEE_MemMove(info.serial_number, sn, sizeof(info.serial_number));
400030e7392SEtienne Carriere 	pad_str(info.serial_number, sizeof(info.serial_number));
401030e7392SEtienne Carriere 
402030e7392SEtienne Carriere 	TEE_MemMove(info.label, token->db_main->label, sizeof(info.label));
403030e7392SEtienne Carriere 
404030e7392SEtienne Carriere 	info.flags = token->db_main->flags;
405030e7392SEtienne Carriere 	info.session_count = token->session_count;
406030e7392SEtienne Carriere 	info.rw_session_count = token->rw_session_count;
407030e7392SEtienne Carriere 
408030e7392SEtienne Carriere 	TEE_MemMove(out->memref.buffer, &info, sizeof(info));
409030e7392SEtienne Carriere 
410030e7392SEtienne Carriere 	return PKCS11_CKR_OK;
411030e7392SEtienne Carriere }
4126f74919dSEtienne Carriere 
4136f74919dSEtienne Carriere static void dmsg_print_supported_mechanism(unsigned int token_id __maybe_unused,
4146f74919dSEtienne Carriere 					   uint32_t *array __maybe_unused,
4156f74919dSEtienne Carriere 					   size_t count __maybe_unused)
4166f74919dSEtienne Carriere {
4176f74919dSEtienne Carriere 	size_t __maybe_unused n = 0;
4186f74919dSEtienne Carriere 
4196f74919dSEtienne Carriere 	if (TRACE_LEVEL < TRACE_DEBUG)
4206f74919dSEtienne Carriere 		return;
4216f74919dSEtienne Carriere 
4226f74919dSEtienne Carriere 	for (n = 0; n < count; n++)
4236f74919dSEtienne Carriere 		DMSG("PKCS11 token %"PRIu32": mechanism 0x%04"PRIx32": %s",
4246f74919dSEtienne Carriere 		     token_id, array[n], id2str_mechanism(array[n]));
4256f74919dSEtienne Carriere }
4266f74919dSEtienne Carriere 
4274daf39b3SJens Wiklander enum pkcs11_rc entry_ck_token_mecha_ids(uint32_t ptypes, TEE_Param *params)
4286f74919dSEtienne Carriere {
4296f74919dSEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
4306f74919dSEtienne Carriere 						TEE_PARAM_TYPE_NONE,
4316f74919dSEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
4326f74919dSEtienne Carriere 						TEE_PARAM_TYPE_NONE);
43339b43b78SJens Wiklander 	TEE_Param *ctrl = params;
43439b43b78SJens Wiklander 	TEE_Param *out = params + 2;
4354daf39b3SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
4366f74919dSEtienne Carriere 	struct serialargs ctrlargs = { };
4376f74919dSEtienne Carriere 	uint32_t token_id = 0;
4386f74919dSEtienne Carriere 	struct ck_token __maybe_unused *token = NULL;
4396f74919dSEtienne Carriere 	size_t count = 0;
4406f74919dSEtienne Carriere 	uint32_t *array = NULL;
4416f74919dSEtienne Carriere 
4426f74919dSEtienne Carriere 	if (ptypes != exp_pt)
4436f74919dSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
4446f74919dSEtienne Carriere 
4456f74919dSEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
4466f74919dSEtienne Carriere 
4474daf39b3SJens Wiklander 	rc = serialargs_get(&ctrlargs, &token_id, sizeof(token_id));
4484daf39b3SJens Wiklander 	if (rc)
4494daf39b3SJens Wiklander 		return rc;
4506f74919dSEtienne Carriere 
4516f74919dSEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
4526f74919dSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
4536f74919dSEtienne Carriere 
4546f74919dSEtienne Carriere 	token = get_token(token_id);
4556f74919dSEtienne Carriere 	if (!token)
4566f74919dSEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
4576f74919dSEtienne Carriere 
4586f74919dSEtienne Carriere 	count = out->memref.size / sizeof(*array);
4596f74919dSEtienne Carriere 	array = tee_malloc_mechanism_list(&count);
4606f74919dSEtienne Carriere 
4616f74919dSEtienne Carriere 	if (out->memref.size < count * sizeof(*array)) {
4626f74919dSEtienne Carriere 		assert(!array);
4636f74919dSEtienne Carriere 		out->memref.size = count * sizeof(*array);
4646459f267SEtienne Carriere 		if (out->memref.buffer)
4656f74919dSEtienne Carriere 			return PKCS11_CKR_BUFFER_TOO_SMALL;
4666459f267SEtienne Carriere 		else
4676459f267SEtienne Carriere 			return PKCS11_CKR_OK;
4686f74919dSEtienne Carriere 	}
4696f74919dSEtienne Carriere 
4706f74919dSEtienne Carriere 	if (!array)
4716f74919dSEtienne Carriere 		return PKCS11_CKR_DEVICE_MEMORY;
4726f74919dSEtienne Carriere 
4736f74919dSEtienne Carriere 	dmsg_print_supported_mechanism(token_id, array, count);
4746f74919dSEtienne Carriere 
4756f74919dSEtienne Carriere 	out->memref.size = count * sizeof(*array);
4766f74919dSEtienne Carriere 	TEE_MemMove(out->memref.buffer, array, out->memref.size);
4776f74919dSEtienne Carriere 
4786f74919dSEtienne Carriere 	TEE_Free(array);
4796f74919dSEtienne Carriere 
4804daf39b3SJens Wiklander 	return rc;
4816f74919dSEtienne Carriere }
4821d3ebedbSEtienne Carriere 
4834daf39b3SJens Wiklander enum pkcs11_rc entry_ck_token_mecha_info(uint32_t ptypes, TEE_Param *params)
4841d3ebedbSEtienne Carriere {
4851d3ebedbSEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
4861d3ebedbSEtienne Carriere 						TEE_PARAM_TYPE_NONE,
4871d3ebedbSEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
4881d3ebedbSEtienne Carriere 						TEE_PARAM_TYPE_NONE);
48939b43b78SJens Wiklander 	TEE_Param *ctrl = params;
49039b43b78SJens Wiklander 	TEE_Param *out = params + 2;
4914daf39b3SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
4921d3ebedbSEtienne Carriere 	struct serialargs ctrlargs = { };
4931d3ebedbSEtienne Carriere 	uint32_t token_id = 0;
4941d3ebedbSEtienne Carriere 	uint32_t type = 0;
4951d3ebedbSEtienne Carriere 	struct ck_token *token = NULL;
4961d3ebedbSEtienne Carriere 	struct pkcs11_mechanism_info info = { };
4971d3ebedbSEtienne Carriere 
4981d3ebedbSEtienne Carriere 	if (ptypes != exp_pt || out->memref.size != sizeof(info))
4991d3ebedbSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
5001d3ebedbSEtienne Carriere 
5011d3ebedbSEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
5021d3ebedbSEtienne Carriere 
5034daf39b3SJens Wiklander 	rc = serialargs_get(&ctrlargs, &token_id, sizeof(uint32_t));
5044daf39b3SJens Wiklander 	if (rc)
5054daf39b3SJens Wiklander 		return rc;
5061d3ebedbSEtienne Carriere 
5074daf39b3SJens Wiklander 	rc = serialargs_get(&ctrlargs, &type, sizeof(uint32_t));
5084daf39b3SJens Wiklander 	if (rc)
5094daf39b3SJens Wiklander 		return rc;
5101d3ebedbSEtienne Carriere 
5111d3ebedbSEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
5121d3ebedbSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
5131d3ebedbSEtienne Carriere 
5141d3ebedbSEtienne Carriere 	token = get_token(token_id);
5151d3ebedbSEtienne Carriere 	if (!token)
5161d3ebedbSEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
5171d3ebedbSEtienne Carriere 
5181d3ebedbSEtienne Carriere 	if (!mechanism_is_valid(type))
5191d3ebedbSEtienne Carriere 		return PKCS11_CKR_MECHANISM_INVALID;
5201d3ebedbSEtienne Carriere 
5211d3ebedbSEtienne Carriere 	info.flags = mechanism_supported_flags(type);
5221d3ebedbSEtienne Carriere 
5232d0cd829SRuchika Gupta 	pkcs11_mechanism_supported_key_sizes(type, &info.min_key_size,
5241d3ebedbSEtienne Carriere 					     &info.max_key_size);
5251d3ebedbSEtienne Carriere 
5261d3ebedbSEtienne Carriere 	TEE_MemMove(out->memref.buffer, &info, sizeof(info));
5271d3ebedbSEtienne Carriere 
5281d3ebedbSEtienne Carriere 	DMSG("PKCS11 token %"PRIu32": mechanism 0x%"PRIx32" info",
5291d3ebedbSEtienne Carriere 	     token_id, type);
5301d3ebedbSEtienne Carriere 
5311d3ebedbSEtienne Carriere 	return PKCS11_CKR_OK;
5321d3ebedbSEtienne Carriere }
5336e4f8f17SEtienne Carriere 
5346e4f8f17SEtienne Carriere /* Select the ReadOnly or ReadWrite state for session login state */
5356e4f8f17SEtienne Carriere static void set_session_state(struct pkcs11_client *client,
5366e4f8f17SEtienne Carriere 			      struct pkcs11_session *session, bool readonly)
5376e4f8f17SEtienne Carriere {
5386e4f8f17SEtienne Carriere 	struct pkcs11_session *sess = NULL;
5396e4f8f17SEtienne Carriere 	enum pkcs11_session_state state = PKCS11_CKS_RO_PUBLIC_SESSION;
5406e4f8f17SEtienne Carriere 
5416e4f8f17SEtienne Carriere 	/* Default to public session if no session already registered */
5426e4f8f17SEtienne Carriere 	if (readonly)
5436e4f8f17SEtienne Carriere 		state = PKCS11_CKS_RO_PUBLIC_SESSION;
5446e4f8f17SEtienne Carriere 	else
5456e4f8f17SEtienne Carriere 		state = PKCS11_CKS_RW_PUBLIC_SESSION;
5466e4f8f17SEtienne Carriere 
5476e4f8f17SEtienne Carriere 	/*
5486e4f8f17SEtienne Carriere 	 * No need to check all client sessions, the first found in
5496e4f8f17SEtienne Carriere 	 * target token gives client login configuration.
5506e4f8f17SEtienne Carriere 	 */
5516e4f8f17SEtienne Carriere 	TAILQ_FOREACH(sess, &client->session_list, link) {
5526e4f8f17SEtienne Carriere 		assert(sess != session);
5536e4f8f17SEtienne Carriere 
5546e4f8f17SEtienne Carriere 		if (sess->token == session->token) {
5556e4f8f17SEtienne Carriere 			switch (sess->state) {
5566e4f8f17SEtienne Carriere 			case PKCS11_CKS_RW_PUBLIC_SESSION:
5576e4f8f17SEtienne Carriere 			case PKCS11_CKS_RO_PUBLIC_SESSION:
5586e4f8f17SEtienne Carriere 				if (readonly)
5596e4f8f17SEtienne Carriere 					state = PKCS11_CKS_RO_PUBLIC_SESSION;
5606e4f8f17SEtienne Carriere 				else
5616e4f8f17SEtienne Carriere 					state = PKCS11_CKS_RW_PUBLIC_SESSION;
5626e4f8f17SEtienne Carriere 				break;
5636e4f8f17SEtienne Carriere 			case PKCS11_CKS_RO_USER_FUNCTIONS:
5646e4f8f17SEtienne Carriere 			case PKCS11_CKS_RW_USER_FUNCTIONS:
5656e4f8f17SEtienne Carriere 				if (readonly)
5666e4f8f17SEtienne Carriere 					state = PKCS11_CKS_RO_USER_FUNCTIONS;
5676e4f8f17SEtienne Carriere 				else
5686e4f8f17SEtienne Carriere 					state = PKCS11_CKS_RW_USER_FUNCTIONS;
5696e4f8f17SEtienne Carriere 				break;
5706e4f8f17SEtienne Carriere 			case PKCS11_CKS_RW_SO_FUNCTIONS:
5716e4f8f17SEtienne Carriere 				if (readonly)
5726e4f8f17SEtienne Carriere 					TEE_Panic(0);
5736e4f8f17SEtienne Carriere 				else
5746e4f8f17SEtienne Carriere 					state = PKCS11_CKS_RW_SO_FUNCTIONS;
5756e4f8f17SEtienne Carriere 				break;
5766e4f8f17SEtienne Carriere 			default:
5776e4f8f17SEtienne Carriere 				TEE_Panic(0);
5786e4f8f17SEtienne Carriere 			}
5796e4f8f17SEtienne Carriere 			break;
5806e4f8f17SEtienne Carriere 		}
5816e4f8f17SEtienne Carriere 	}
5826e4f8f17SEtienne Carriere 
5836e4f8f17SEtienne Carriere 	session->state = state;
5846e4f8f17SEtienne Carriere }
5856e4f8f17SEtienne Carriere 
5864daf39b3SJens Wiklander enum pkcs11_rc entry_ck_open_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_MEMREF_OUTPUT,
5926e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
59339b43b78SJens Wiklander 	TEE_Param *ctrl = params;
59439b43b78SJens Wiklander 	TEE_Param *out = params + 2;
5954daf39b3SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
5966e4f8f17SEtienne Carriere 	struct serialargs ctrlargs = { };
5976e4f8f17SEtienne Carriere 	uint32_t token_id = 0;
5986e4f8f17SEtienne Carriere 	uint32_t flags = 0;
5996e4f8f17SEtienne Carriere 	struct ck_token *token = NULL;
6006e4f8f17SEtienne Carriere 	struct pkcs11_session *session = NULL;
6016e4f8f17SEtienne Carriere 	bool readonly = false;
6026e4f8f17SEtienne Carriere 
6036e4f8f17SEtienne Carriere 	if (!client || ptypes != exp_pt ||
6046e4f8f17SEtienne Carriere 	    out->memref.size != sizeof(session->handle))
6056e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
6066e4f8f17SEtienne Carriere 
6076e4f8f17SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
6086e4f8f17SEtienne Carriere 
6094daf39b3SJens Wiklander 	rc = serialargs_get(&ctrlargs, &token_id, sizeof(token_id));
6104daf39b3SJens Wiklander 	if (rc)
6114daf39b3SJens Wiklander 		return rc;
6126e4f8f17SEtienne Carriere 
6134daf39b3SJens Wiklander 	rc = serialargs_get(&ctrlargs, &flags, sizeof(flags));
6144daf39b3SJens Wiklander 	if (rc)
6154daf39b3SJens Wiklander 		return rc;
6166e4f8f17SEtienne Carriere 
6176e4f8f17SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
6186e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
6196e4f8f17SEtienne Carriere 
6206e4f8f17SEtienne Carriere 	token = get_token(token_id);
6216e4f8f17SEtienne Carriere 	if (!token)
6226e4f8f17SEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
6236e4f8f17SEtienne Carriere 
6246e4f8f17SEtienne Carriere 	/* Sanitize session flags */
62508774c86SVesa Jääskeläinen 	if (!(flags & PKCS11_CKFSS_SERIAL_SESSION))
62608774c86SVesa Jääskeläinen 		return PKCS11_CKR_SESSION_PARALLEL_NOT_SUPPORTED;
62708774c86SVesa Jääskeläinen 
62808774c86SVesa Jääskeläinen 	if (flags & ~(PKCS11_CKFSS_RW_SESSION | PKCS11_CKFSS_SERIAL_SESSION))
6296e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
6306e4f8f17SEtienne Carriere 
6316e4f8f17SEtienne Carriere 	readonly = !(flags & PKCS11_CKFSS_RW_SESSION);
6326e4f8f17SEtienne Carriere 
6336e4f8f17SEtienne Carriere 	if (!readonly && token->state == PKCS11_TOKEN_READ_ONLY)
6346e4f8f17SEtienne Carriere 		return PKCS11_CKR_TOKEN_WRITE_PROTECTED;
6356e4f8f17SEtienne Carriere 
6366e4f8f17SEtienne Carriere 	if (readonly) {
6376e4f8f17SEtienne Carriere 		/* Specifically reject read-only session under SO login */
6386e4f8f17SEtienne Carriere 		TAILQ_FOREACH(session, &client->session_list, link)
6396e4f8f17SEtienne Carriere 			if (pkcs11_session_is_so(session))
6406e4f8f17SEtienne Carriere 				return PKCS11_CKR_SESSION_READ_WRITE_SO_EXISTS;
6416e4f8f17SEtienne Carriere 	}
6426e4f8f17SEtienne Carriere 
6436e4f8f17SEtienne Carriere 	session = TEE_Malloc(sizeof(*session), TEE_MALLOC_FILL_ZERO);
6446e4f8f17SEtienne Carriere 	if (!session)
6456e4f8f17SEtienne Carriere 		return PKCS11_CKR_DEVICE_MEMORY;
6466e4f8f17SEtienne Carriere 
6476e4f8f17SEtienne Carriere 	session->handle = handle_get(&client->session_handle_db, session);
6486e4f8f17SEtienne Carriere 	if (!session->handle) {
6496e4f8f17SEtienne Carriere 		TEE_Free(session);
6506e4f8f17SEtienne Carriere 		return PKCS11_CKR_DEVICE_MEMORY;
6516e4f8f17SEtienne Carriere 	}
6526e4f8f17SEtienne Carriere 
6536e4f8f17SEtienne Carriere 	session->token = token;
6546e4f8f17SEtienne Carriere 	session->client = client;
6556e4f8f17SEtienne Carriere 
656b56b3d07SJens Wiklander 	LIST_INIT(&session->object_list);
657b56b3d07SJens Wiklander 
6586e4f8f17SEtienne Carriere 	set_session_state(client, session, readonly);
6596e4f8f17SEtienne Carriere 
6606e4f8f17SEtienne Carriere 	TAILQ_INSERT_HEAD(&client->session_list, session, link);
6616e4f8f17SEtienne Carriere 
6626e4f8f17SEtienne Carriere 	session->token->session_count++;
6636e4f8f17SEtienne Carriere 	if (!readonly)
6646e4f8f17SEtienne Carriere 		session->token->rw_session_count++;
6656e4f8f17SEtienne Carriere 
6666e4f8f17SEtienne Carriere 	TEE_MemMove(out->memref.buffer, &session->handle,
6676e4f8f17SEtienne Carriere 		    sizeof(session->handle));
6686e4f8f17SEtienne Carriere 
6696e4f8f17SEtienne Carriere 	DMSG("Open PKCS11 session %"PRIu32, session->handle);
6706e4f8f17SEtienne Carriere 
6716e4f8f17SEtienne Carriere 	return PKCS11_CKR_OK;
6726e4f8f17SEtienne Carriere }
6736e4f8f17SEtienne Carriere 
6746e4f8f17SEtienne Carriere static void close_ck_session(struct pkcs11_session *session)
6756e4f8f17SEtienne Carriere {
67655e6965cSEtienne Carriere 	release_active_processing(session);
677bc555ee0SVesa Jääskeläinen 	release_session_find_obj_context(session);
67855e6965cSEtienne Carriere 
679bc555ee0SVesa Jääskeläinen 	/* Release all session objects */
680b56b3d07SJens Wiklander 	while (!LIST_EMPTY(&session->object_list))
681b56b3d07SJens Wiklander 		destroy_object(session,
682b56b3d07SJens Wiklander 			       LIST_FIRST(&session->object_list), true);
683b56b3d07SJens Wiklander 
6846e4f8f17SEtienne Carriere 	TAILQ_REMOVE(&session->client->session_list, session, link);
6856e4f8f17SEtienne Carriere 	handle_put(&session->client->session_handle_db, session->handle);
6866e4f8f17SEtienne Carriere 
6876e4f8f17SEtienne Carriere 	session->token->session_count--;
6886e4f8f17SEtienne Carriere 	if (pkcs11_session_is_read_write(session))
6896e4f8f17SEtienne Carriere 		session->token->rw_session_count--;
6906e4f8f17SEtienne Carriere 
6916e4f8f17SEtienne Carriere 	DMSG("Close PKCS11 session %"PRIu32, session->handle);
6929325ea3dSJerome Forissier 
6939325ea3dSJerome Forissier 	TEE_Free(session);
6946e4f8f17SEtienne Carriere }
6956e4f8f17SEtienne Carriere 
6964daf39b3SJens Wiklander enum pkcs11_rc entry_ck_close_session(struct pkcs11_client *client,
6976e4f8f17SEtienne Carriere 				      uint32_t ptypes, TEE_Param *params)
6986e4f8f17SEtienne Carriere {
6996e4f8f17SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
7006e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
7016e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
7026e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
70339b43b78SJens Wiklander 	TEE_Param *ctrl = params;
7044daf39b3SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
7056e4f8f17SEtienne Carriere 	struct serialargs ctrlargs = { };
7066e4f8f17SEtienne Carriere 	struct pkcs11_session *session = NULL;
7076e4f8f17SEtienne Carriere 
7086e4f8f17SEtienne Carriere 	if (!client || ptypes != exp_pt)
7096e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
7106e4f8f17SEtienne Carriere 
7116e4f8f17SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
7126e4f8f17SEtienne Carriere 
7134daf39b3SJens Wiklander 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
7144daf39b3SJens Wiklander 	if (rc)
7154daf39b3SJens Wiklander 		return rc;
7166e4f8f17SEtienne Carriere 
7176e4f8f17SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
7186e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
7196e4f8f17SEtienne Carriere 
7206e4f8f17SEtienne Carriere 	close_ck_session(session);
7216e4f8f17SEtienne Carriere 
7226e4f8f17SEtienne Carriere 	return PKCS11_CKR_OK;
7236e4f8f17SEtienne Carriere }
7246e4f8f17SEtienne Carriere 
7254daf39b3SJens Wiklander enum pkcs11_rc entry_ck_close_all_sessions(struct pkcs11_client *client,
7266e4f8f17SEtienne Carriere 					   uint32_t ptypes, TEE_Param *params)
7276e4f8f17SEtienne Carriere {
7286e4f8f17SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
7296e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
7306e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
7316e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
73239b43b78SJens Wiklander 	TEE_Param *ctrl = params;
7334daf39b3SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
7346e4f8f17SEtienne Carriere 	struct serialargs ctrlargs = { };
7356e4f8f17SEtienne Carriere 	uint32_t token_id = 0;
7366e4f8f17SEtienne Carriere 	struct ck_token *token = NULL;
7376e4f8f17SEtienne Carriere 	struct pkcs11_session *session = NULL;
7386e4f8f17SEtienne Carriere 	struct pkcs11_session *next = NULL;
7396e4f8f17SEtienne Carriere 
7406e4f8f17SEtienne Carriere 	if (!client || ptypes != exp_pt)
7416e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
7426e4f8f17SEtienne Carriere 
7436e4f8f17SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
7446e4f8f17SEtienne Carriere 
7454daf39b3SJens Wiklander 	rc = serialargs_get(&ctrlargs, &token_id, sizeof(uint32_t));
7464daf39b3SJens Wiklander 	if (rc)
7474daf39b3SJens Wiklander 		return rc;
7486e4f8f17SEtienne Carriere 
7496e4f8f17SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
7506e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
7516e4f8f17SEtienne Carriere 
7526e4f8f17SEtienne Carriere 	token = get_token(token_id);
7536e4f8f17SEtienne Carriere 	if (!token)
7546e4f8f17SEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
7556e4f8f17SEtienne Carriere 
7566e4f8f17SEtienne Carriere 	DMSG("Close all sessions for PKCS11 token %"PRIu32, token_id);
7576e4f8f17SEtienne Carriere 
7586e4f8f17SEtienne Carriere 	TAILQ_FOREACH_SAFE(session, &client->session_list, link, next)
7596e4f8f17SEtienne Carriere 		if (session->token == token)
7606e4f8f17SEtienne Carriere 			close_ck_session(session);
7616e4f8f17SEtienne Carriere 
7626e4f8f17SEtienne Carriere 	return PKCS11_CKR_OK;
7636e4f8f17SEtienne Carriere }
7646e4f8f17SEtienne Carriere 
7654daf39b3SJens Wiklander enum pkcs11_rc entry_ck_session_info(struct pkcs11_client *client,
7666e4f8f17SEtienne Carriere 				     uint32_t ptypes, TEE_Param *params)
7676e4f8f17SEtienne Carriere {
7686e4f8f17SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
7696e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
7706e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
7716e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
77239b43b78SJens Wiklander 	TEE_Param *ctrl = params;
77339b43b78SJens Wiklander 	TEE_Param *out = params + 2;
7744daf39b3SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
7756e4f8f17SEtienne Carriere 	struct serialargs ctrlargs = { };
7766e4f8f17SEtienne Carriere 	struct pkcs11_session *session = NULL;
7776e4f8f17SEtienne Carriere 	struct pkcs11_session_info info = {
7786e4f8f17SEtienne Carriere 		.flags = PKCS11_CKFSS_SERIAL_SESSION,
7796e4f8f17SEtienne Carriere 	};
7806e4f8f17SEtienne Carriere 
7816e4f8f17SEtienne Carriere 	if (!client || ptypes != exp_pt || out->memref.size != sizeof(info))
7826e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
7836e4f8f17SEtienne Carriere 
7846e4f8f17SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
7856e4f8f17SEtienne Carriere 
7864daf39b3SJens Wiklander 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
7874daf39b3SJens Wiklander 	if (rc)
7884daf39b3SJens Wiklander 		return rc;
7896e4f8f17SEtienne Carriere 
7906e4f8f17SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
7916e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
7926e4f8f17SEtienne Carriere 
7936e4f8f17SEtienne Carriere 	info.slot_id = get_token_id(session->token);
7946e4f8f17SEtienne Carriere 	info.state = session->state;
7956e4f8f17SEtienne Carriere 	if (pkcs11_session_is_read_write(session))
7966e4f8f17SEtienne Carriere 		info.flags |= PKCS11_CKFSS_RW_SESSION;
7976e4f8f17SEtienne Carriere 
7986e4f8f17SEtienne Carriere 	TEE_MemMove(out->memref.buffer, &info, sizeof(info));
7996e4f8f17SEtienne Carriere 
8006e4f8f17SEtienne Carriere 	DMSG("Get find on PKCS11 session %"PRIu32, session->handle);
8016e4f8f17SEtienne Carriere 
8026e4f8f17SEtienne Carriere 	return PKCS11_CKR_OK;
8036e4f8f17SEtienne Carriere }
804f485be04SJens Wiklander 
8054daf39b3SJens Wiklander enum pkcs11_rc entry_ck_token_initialize(uint32_t ptypes, TEE_Param *params)
806f485be04SJens Wiklander {
807f485be04SJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
808f485be04SJens Wiklander 						TEE_PARAM_TYPE_NONE,
809f485be04SJens Wiklander 						TEE_PARAM_TYPE_NONE,
810f485be04SJens Wiklander 						TEE_PARAM_TYPE_NONE);
811f485be04SJens Wiklander 	char label[PKCS11_TOKEN_LABEL_SIZE] = { 0 };
812f485be04SJens Wiklander 	struct pkcs11_client *client = NULL;
813f485be04SJens Wiklander 	struct pkcs11_session *sess = NULL;
814f485be04SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
815f485be04SJens Wiklander 	struct serialargs ctrlargs = { };
816f485be04SJens Wiklander 	struct ck_token *token = NULL;
817f485be04SJens Wiklander 	TEE_Param *ctrl = params;
818f485be04SJens Wiklander 	uint32_t token_id = 0;
819f485be04SJens Wiklander 	uint32_t pin_size = 0;
820f485be04SJens Wiklander 	void *pin = NULL;
8217f12c782SRobin van der Gracht 	struct pkcs11_object *obj = NULL;
822f485be04SJens Wiklander 
823f485be04SJens Wiklander 	if (ptypes != exp_pt)
824f485be04SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
825f485be04SJens Wiklander 
826f485be04SJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
827f485be04SJens Wiklander 
828f485be04SJens Wiklander 	rc = serialargs_get(&ctrlargs, &token_id, sizeof(uint32_t));
829f485be04SJens Wiklander 	if (rc)
830f485be04SJens Wiklander 		return rc;
831f485be04SJens Wiklander 
832f485be04SJens Wiklander 	rc = serialargs_get(&ctrlargs, &pin_size, sizeof(uint32_t));
833f485be04SJens Wiklander 	if (rc)
834f485be04SJens Wiklander 		return rc;
835f485be04SJens Wiklander 
836f485be04SJens Wiklander 	rc = serialargs_get(&ctrlargs, &label, PKCS11_TOKEN_LABEL_SIZE);
837f485be04SJens Wiklander 	if (rc)
838f485be04SJens Wiklander 		return rc;
839f485be04SJens Wiklander 
840f485be04SJens Wiklander 	rc = serialargs_get_ptr(&ctrlargs, &pin, pin_size);
841f485be04SJens Wiklander 	if (rc)
842f485be04SJens Wiklander 		return rc;
843f485be04SJens Wiklander 
844f485be04SJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs))
845f485be04SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
846f485be04SJens Wiklander 
847f485be04SJens Wiklander 	token = get_token(token_id);
848f485be04SJens Wiklander 	if (!token)
849f485be04SJens Wiklander 		return PKCS11_CKR_SLOT_ID_INVALID;
850f485be04SJens Wiklander 
851f485be04SJens Wiklander 	if (token->db_main->flags & PKCS11_CKFT_SO_PIN_LOCKED) {
852f485be04SJens Wiklander 		IMSG("Token %"PRIu32": SO PIN locked", token_id);
853f485be04SJens Wiklander 		return PKCS11_CKR_PIN_LOCKED;
854f485be04SJens Wiklander 	}
855f485be04SJens Wiklander 
856f485be04SJens Wiklander 	/* Check there's no open session on this token */
857f485be04SJens Wiklander 	TAILQ_FOREACH(client, &pkcs11_client_list, link)
858f485be04SJens Wiklander 		TAILQ_FOREACH(sess, &client->session_list, link)
859f485be04SJens Wiklander 			if (sess->token == token)
860f485be04SJens Wiklander 				return PKCS11_CKR_SESSION_EXISTS;
861f485be04SJens Wiklander 
862f1105cc5SVesa Jääskeläinen 	/* Verify authentication if token is already initialized */
863f1105cc5SVesa Jääskeläinen 	if (token->db_main->flags & PKCS11_CKFT_TOKEN_INITIALIZED) {
864f1105cc5SVesa Jääskeläinen 		unsigned int pin_count = 0;
865f1105cc5SVesa Jääskeläinen 
866f1105cc5SVesa Jääskeläinen 		if (IS_ENABLED(CFG_PKCS11_TA_AUTH_TEE_IDENTITY) &&
867f1105cc5SVesa Jääskeläinen 		    (token->db_main->flags &
868f1105cc5SVesa Jääskeläinen 		     PKCS11_CKFT_PROTECTED_AUTHENTICATION_PATH)) {
8691a27b197SVesa Jääskeläinen 			/* Check TEE Identity based authentication if enabled */
870f44a7a58SEtienne Carriere 			rc = verify_identity_auth(token, PKCS11_CKU_SO);
8711a27b197SVesa Jääskeläinen 			if (rc)
8721a27b197SVesa Jääskeläinen 				return rc;
873f485be04SJens Wiklander 
874f485be04SJens Wiklander 			goto inited;
875f485be04SJens Wiklander 		}
876f485be04SJens Wiklander 
877f1105cc5SVesa Jääskeläinen 		/* Check PIN based authentication */
878f485be04SJens Wiklander 		rc = verify_pin(PKCS11_CKU_SO, pin, pin_size,
879f485be04SJens Wiklander 				token->db_main->so_pin_salt,
880f485be04SJens Wiklander 				token->db_main->so_pin_hash);
881f1105cc5SVesa Jääskeläinen 		if (!rc)
882f1105cc5SVesa Jääskeläinen 			goto inited;
883f485be04SJens Wiklander 
884f485be04SJens Wiklander 		if (rc != PKCS11_CKR_PIN_INCORRECT)
885f485be04SJens Wiklander 			return rc;
886f485be04SJens Wiklander 
887f485be04SJens Wiklander 		token->db_main->flags |= PKCS11_CKFT_SO_PIN_COUNT_LOW;
888f485be04SJens Wiklander 		token->db_main->so_pin_count++;
889f485be04SJens Wiklander 
890f485be04SJens Wiklander 		pin_count = token->db_main->so_pin_count;
891f485be04SJens Wiklander 		if (pin_count == PKCS11_TOKEN_SO_PIN_COUNT_MAX - 1)
892f485be04SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_SO_PIN_FINAL_TRY;
893f485be04SJens Wiklander 		if (pin_count == PKCS11_TOKEN_SO_PIN_COUNT_MAX)
894f485be04SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_SO_PIN_LOCKED;
895f485be04SJens Wiklander 
896f485be04SJens Wiklander 		update_persistent_db(token);
897f485be04SJens Wiklander 
898f485be04SJens Wiklander 		return PKCS11_CKR_PIN_INCORRECT;
899f485be04SJens Wiklander 	}
900f485be04SJens Wiklander 
901f1105cc5SVesa Jääskeläinen 	/* Initialize SO's authentication */
902f1105cc5SVesa Jääskeläinen 	if (IS_ENABLED(CFG_PKCS11_TA_AUTH_TEE_IDENTITY) && !pin) {
903f1105cc5SVesa Jääskeläinen 		rc = setup_so_identity_auth_from_client(token);
904f1105cc5SVesa Jääskeläinen 		if (rc)
905f1105cc5SVesa Jääskeläinen 			return rc;
906f1105cc5SVesa Jääskeläinen 	} else {
907f1105cc5SVesa Jääskeläinen 		/*
908f1105cc5SVesa Jääskeläinen 		 * The spec doesn't permit returning
909f1105cc5SVesa Jääskeläinen 		 * PKCS11_CKR_PIN_LEN_RANGE for this function, take another
910f1105cc5SVesa Jääskeläinen 		 * error code.
911f1105cc5SVesa Jääskeläinen 		 */
912f1105cc5SVesa Jääskeläinen 		if (pin_size < PKCS11_TOKEN_PIN_SIZE_MIN ||
913f1105cc5SVesa Jääskeläinen 		    pin_size > PKCS11_TOKEN_PIN_SIZE_MAX)
914f1105cc5SVesa Jääskeläinen 			return PKCS11_CKR_ARGUMENTS_BAD;
915f1105cc5SVesa Jääskeläinen 
916f1105cc5SVesa Jääskeläinen 		rc = hash_pin(PKCS11_CKU_SO, pin, pin_size,
917f1105cc5SVesa Jääskeläinen 			      &token->db_main->so_pin_salt,
918f1105cc5SVesa Jääskeläinen 			      token->db_main->so_pin_hash);
919f1105cc5SVesa Jääskeläinen 		if (rc)
920f1105cc5SVesa Jääskeläinen 			return rc;
921f1105cc5SVesa Jääskeläinen 	}
922f1105cc5SVesa Jääskeläinen 
92312253e9eSVesa Jääskeläinen inited:
92412253e9eSVesa Jääskeläinen 	/* Make sure SO PIN counters are zeroed */
925f485be04SJens Wiklander 	token->db_main->flags &= ~(PKCS11_CKFT_SO_PIN_COUNT_LOW |
92612253e9eSVesa Jääskeläinen 				   PKCS11_CKFT_SO_PIN_FINAL_TRY |
92712253e9eSVesa Jääskeläinen 				   PKCS11_CKFT_SO_PIN_LOCKED |
92812253e9eSVesa Jääskeläinen 				   PKCS11_CKFT_SO_PIN_TO_BE_CHANGED);
929f485be04SJens Wiklander 	token->db_main->so_pin_count = 0;
930f485be04SJens Wiklander 
931f485be04SJens Wiklander 	TEE_MemMove(token->db_main->label, label, PKCS11_TOKEN_LABEL_SIZE);
932f485be04SJens Wiklander 	token->db_main->flags |= PKCS11_CKFT_TOKEN_INITIALIZED;
933f485be04SJens Wiklander 	/* Reset user PIN */
934f485be04SJens Wiklander 	token->db_main->user_pin_salt = 0;
935f485be04SJens Wiklander 	token->db_main->flags &= ~(PKCS11_CKFT_USER_PIN_INITIALIZED |
936f485be04SJens Wiklander 				   PKCS11_CKFT_USER_PIN_COUNT_LOW |
937f485be04SJens Wiklander 				   PKCS11_CKFT_USER_PIN_FINAL_TRY |
938f485be04SJens Wiklander 				   PKCS11_CKFT_USER_PIN_LOCKED |
939f485be04SJens Wiklander 				   PKCS11_CKFT_USER_PIN_TO_BE_CHANGED);
940f485be04SJens Wiklander 
941f485be04SJens Wiklander 	update_persistent_db(token);
942f485be04SJens Wiklander 
9437f12c782SRobin van der Gracht 	/* Remove all persistent objects */
9447f12c782SRobin van der Gracht 	while (!LIST_EMPTY(&token->object_list)) {
9457f12c782SRobin van der Gracht 		obj = LIST_FIRST(&token->object_list);
9467f12c782SRobin van der Gracht 
9477f12c782SRobin van der Gracht 		/* Try twice otherwise panic! */
9487f12c782SRobin van der Gracht 		if (unregister_persistent_object(token, obj->uuid) &&
9497f12c782SRobin van der Gracht 		    unregister_persistent_object(token, obj->uuid))
9507f12c782SRobin van der Gracht 			TEE_Panic(0);
9517f12c782SRobin van der Gracht 
9527f12c782SRobin van der Gracht 		cleanup_persistent_object(obj, token);
9537f12c782SRobin van der Gracht 	}
9547f12c782SRobin van der Gracht 
955f485be04SJens Wiklander 	IMSG("PKCS11 token %"PRIu32": initialized", token_id);
956f485be04SJens Wiklander 
957f485be04SJens Wiklander 	return PKCS11_CKR_OK;
958f485be04SJens Wiklander }
959e8dbd92cSJens Wiklander 
960e8dbd92cSJens Wiklander static enum pkcs11_rc set_pin(struct pkcs11_session *session,
961e8dbd92cSJens Wiklander 			      uint8_t *new_pin, size_t new_pin_size,
962e8dbd92cSJens Wiklander 			      enum pkcs11_user_type user_type)
963e8dbd92cSJens Wiklander {
9641e497011SVesa Jääskeläinen 	struct ck_token *token = session->token;
965e8dbd92cSJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
966e8dbd92cSJens Wiklander 	uint32_t flags_clear = 0;
967e8dbd92cSJens Wiklander 	uint32_t flags_set = 0;
968e8dbd92cSJens Wiklander 
9691e497011SVesa Jääskeläinen 	if (token->db_main->flags & PKCS11_CKFT_WRITE_PROTECTED)
970e8dbd92cSJens Wiklander 		return PKCS11_CKR_TOKEN_WRITE_PROTECTED;
971e8dbd92cSJens Wiklander 
972e8dbd92cSJens Wiklander 	if (!pkcs11_session_is_read_write(session))
973e8dbd92cSJens Wiklander 		return PKCS11_CKR_SESSION_READ_ONLY;
974e8dbd92cSJens Wiklander 
9751a27b197SVesa Jääskeläinen 	if (IS_ENABLED(CFG_PKCS11_TA_AUTH_TEE_IDENTITY) &&
976*920e0127SVesa Jääskeläinen 	    (token->db_main->flags &
977*920e0127SVesa Jääskeläinen 	     PKCS11_CKFT_PROTECTED_AUTHENTICATION_PATH)) {
978*920e0127SVesa Jääskeläinen 		rc = setup_identity_auth_from_pin(token, user_type,
979*920e0127SVesa Jääskeläinen 						  new_pin, new_pin_size);
980*920e0127SVesa Jääskeläinen 		if (rc == PKCS11_CKR_OK) {
981*920e0127SVesa Jääskeläinen 			goto update_db;
982*920e0127SVesa Jääskeläinen 		} else if (rc == PKCS11_CKR_PIN_INVALID &&
983*920e0127SVesa Jääskeläinen 			   !(token->db_main->flags &
984*920e0127SVesa Jääskeläinen 			     PKCS11_CKFT_USER_PIN_INITIALIZED)) {
985*920e0127SVesa Jääskeläinen 			/*
986*920e0127SVesa Jääskeläinen 			 * PIN was not compatible with TEE Identity
987*920e0127SVesa Jääskeläinen 			 * Authentication syntax so let's assume it might be a
988*920e0127SVesa Jääskeläinen 			 * new SO PIN to switch the authentication mode.
989*920e0127SVesa Jääskeläinen 			 */
990*920e0127SVesa Jääskeläinen 
991*920e0127SVesa Jääskeläinen 			/* Update mode flag if all PIN checks pass */
992*920e0127SVesa Jääskeläinen 			flags_clear |=
993*920e0127SVesa Jääskeläinen 				PKCS11_CKFT_PROTECTED_AUTHENTICATION_PATH;
994*920e0127SVesa Jääskeläinen 		} else {
9951a27b197SVesa Jääskeläinen 			return rc;
996*920e0127SVesa Jääskeläinen 		}
997*920e0127SVesa Jääskeläinen 	} else if ((user_type == PKCS11_CKU_SO) && !new_pin &&
998*920e0127SVesa Jääskeläinen 		   IS_ENABLED(CFG_PKCS11_TA_AUTH_TEE_IDENTITY) &&
999*920e0127SVesa Jääskeläinen 		   !(token->db_main->flags &
1000*920e0127SVesa Jääskeläinen 		     PKCS11_CKFT_USER_PIN_INITIALIZED)) {
1001*920e0127SVesa Jääskeläinen 		/*
1002*920e0127SVesa Jääskeläinen 		 * Allow changing of token authentication mode before user pin
1003*920e0127SVesa Jääskeläinen 		 * has been initialized.
1004*920e0127SVesa Jääskeläinen 		 */
1005*920e0127SVesa Jääskeläinen 
1006*920e0127SVesa Jääskeläinen 		/*
1007*920e0127SVesa Jääskeläinen 		 * Set protected authentication path temporary until
1008*920e0127SVesa Jääskeläinen 		 * finalized.
1009*920e0127SVesa Jääskeläinen 		 */
1010*920e0127SVesa Jääskeläinen 		token->db_main->flags |=
1011*920e0127SVesa Jääskeläinen 			PKCS11_CKFT_PROTECTED_AUTHENTICATION_PATH;
1012*920e0127SVesa Jääskeläinen 
1013*920e0127SVesa Jääskeläinen 		/*
1014*920e0127SVesa Jääskeläinen 		 * Setup authentication from currently active TEE Client
1015*920e0127SVesa Jääskeläinen 		 * Identity.
1016*920e0127SVesa Jääskeläinen 		 */
1017*920e0127SVesa Jääskeläinen 		rc = setup_identity_auth_from_pin(token, PKCS11_CKU_SO,
1018*920e0127SVesa Jääskeläinen 						  NULL, 0);
1019*920e0127SVesa Jääskeläinen 		if (rc) {
1020*920e0127SVesa Jääskeläinen 			/*
1021*920e0127SVesa Jääskeläinen 			 * Failed to setup protected authentication path so
1022*920e0127SVesa Jääskeläinen 			 * clear the temporary flag.
1023*920e0127SVesa Jääskeläinen 			 */
1024*920e0127SVesa Jääskeläinen 			token->db_main->flags &=
1025*920e0127SVesa Jääskeläinen 				~PKCS11_CKFT_PROTECTED_AUTHENTICATION_PATH;
1026*920e0127SVesa Jääskeläinen 			return rc;
1027*920e0127SVesa Jääskeläinen 		}
10281a27b197SVesa Jääskeläinen 
10291a27b197SVesa Jääskeläinen 		goto update_db;
10301a27b197SVesa Jääskeläinen 	}
10311a27b197SVesa Jääskeläinen 
1032e8dbd92cSJens Wiklander 	if (new_pin_size < PKCS11_TOKEN_PIN_SIZE_MIN ||
1033e8dbd92cSJens Wiklander 	    new_pin_size > PKCS11_TOKEN_PIN_SIZE_MAX)
1034e8dbd92cSJens Wiklander 		return PKCS11_CKR_PIN_LEN_RANGE;
1035e8dbd92cSJens Wiklander 
1036e8dbd92cSJens Wiklander 	switch (user_type) {
1037e8dbd92cSJens Wiklander 	case PKCS11_CKU_SO:
1038e8dbd92cSJens Wiklander 		rc = hash_pin(user_type, new_pin, new_pin_size,
10391e497011SVesa Jääskeläinen 			      &token->db_main->so_pin_salt,
10401e497011SVesa Jääskeläinen 			      token->db_main->so_pin_hash);
1041e8dbd92cSJens Wiklander 		if (rc)
1042e8dbd92cSJens Wiklander 			return rc;
10431e497011SVesa Jääskeläinen 		token->db_main->so_pin_count = 0;
1044*920e0127SVesa Jääskeläinen 		flags_clear |= PKCS11_CKFT_SO_PIN_COUNT_LOW |
1045e8dbd92cSJens Wiklander 			       PKCS11_CKFT_SO_PIN_FINAL_TRY |
1046e8dbd92cSJens Wiklander 			       PKCS11_CKFT_SO_PIN_LOCKED |
1047e8dbd92cSJens Wiklander 			       PKCS11_CKFT_SO_PIN_TO_BE_CHANGED;
1048e8dbd92cSJens Wiklander 		break;
1049e8dbd92cSJens Wiklander 	case PKCS11_CKU_USER:
1050e8dbd92cSJens Wiklander 		rc = hash_pin(user_type, new_pin, new_pin_size,
10511e497011SVesa Jääskeläinen 			      &token->db_main->user_pin_salt,
10521e497011SVesa Jääskeläinen 			      token->db_main->user_pin_hash);
1053e8dbd92cSJens Wiklander 		if (rc)
1054e8dbd92cSJens Wiklander 			return rc;
10551e497011SVesa Jääskeläinen 		token->db_main->user_pin_count = 0;
1056*920e0127SVesa Jääskeläinen 		flags_clear |= PKCS11_CKFT_USER_PIN_COUNT_LOW |
1057e8dbd92cSJens Wiklander 			       PKCS11_CKFT_USER_PIN_FINAL_TRY |
1058e8dbd92cSJens Wiklander 			       PKCS11_CKFT_USER_PIN_LOCKED |
1059e8dbd92cSJens Wiklander 			       PKCS11_CKFT_USER_PIN_TO_BE_CHANGED;
1060*920e0127SVesa Jääskeläinen 		flags_set |= PKCS11_CKFT_USER_PIN_INITIALIZED;
1061e8dbd92cSJens Wiklander 		break;
1062e8dbd92cSJens Wiklander 	default:
1063e8dbd92cSJens Wiklander 		return PKCS11_CKR_FUNCTION_FAILED;
1064e8dbd92cSJens Wiklander 	}
1065e8dbd92cSJens Wiklander 
10661a27b197SVesa Jääskeläinen update_db:
10671e497011SVesa Jääskeläinen 	token->db_main->flags &= ~flags_clear;
10681e497011SVesa Jääskeläinen 	token->db_main->flags |= flags_set;
1069e8dbd92cSJens Wiklander 
10701e497011SVesa Jääskeläinen 	update_persistent_db(token);
1071e8dbd92cSJens Wiklander 
1072e8dbd92cSJens Wiklander 	return PKCS11_CKR_OK;
1073e8dbd92cSJens Wiklander }
1074e8dbd92cSJens Wiklander 
10754daf39b3SJens Wiklander enum pkcs11_rc entry_ck_init_pin(struct pkcs11_client *client,
1076e8dbd92cSJens Wiklander 				 uint32_t ptypes, TEE_Param *params)
1077e8dbd92cSJens Wiklander {
1078e8dbd92cSJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
1079e8dbd92cSJens Wiklander 						TEE_PARAM_TYPE_NONE,
1080e8dbd92cSJens Wiklander 						TEE_PARAM_TYPE_NONE,
1081e8dbd92cSJens Wiklander 						TEE_PARAM_TYPE_NONE);
1082e8dbd92cSJens Wiklander 	struct pkcs11_session *session = NULL;
1083e8dbd92cSJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
1084e8dbd92cSJens Wiklander 	struct serialargs ctrlargs = { };
1085e8dbd92cSJens Wiklander 	TEE_Param *ctrl = params;
1086e8dbd92cSJens Wiklander 	uint32_t pin_size = 0;
1087e8dbd92cSJens Wiklander 	void *pin = NULL;
1088e8dbd92cSJens Wiklander 
1089e8dbd92cSJens Wiklander 	if (!client || ptypes != exp_pt)
1090e8dbd92cSJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
1091e8dbd92cSJens Wiklander 
1092e8dbd92cSJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
1093e8dbd92cSJens Wiklander 
1094f40f331fSEtienne Carriere 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
1095e8dbd92cSJens Wiklander 	if (rc)
1096e8dbd92cSJens Wiklander 		return rc;
1097e8dbd92cSJens Wiklander 
1098e8dbd92cSJens Wiklander 	rc = serialargs_get(&ctrlargs, &pin_size, sizeof(uint32_t));
1099e8dbd92cSJens Wiklander 	if (rc)
1100e8dbd92cSJens Wiklander 		return rc;
1101e8dbd92cSJens Wiklander 
1102e8dbd92cSJens Wiklander 	rc = serialargs_get_ptr(&ctrlargs, &pin, pin_size);
1103e8dbd92cSJens Wiklander 	if (rc)
1104e8dbd92cSJens Wiklander 		return rc;
1105e8dbd92cSJens Wiklander 
1106e8dbd92cSJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs))
1107e8dbd92cSJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
1108e8dbd92cSJens Wiklander 
1109e8dbd92cSJens Wiklander 	if (!pkcs11_session_is_so(session))
1110e8dbd92cSJens Wiklander 		return PKCS11_CKR_USER_NOT_LOGGED_IN;
1111e8dbd92cSJens Wiklander 
1112e8dbd92cSJens Wiklander 	assert(session->token->db_main->flags & PKCS11_CKFT_TOKEN_INITIALIZED);
1113e8dbd92cSJens Wiklander 
1114f40f331fSEtienne Carriere 	IMSG("PKCS11 session %"PRIu32": init PIN", session->handle);
1115e8dbd92cSJens Wiklander 
1116e8dbd92cSJens Wiklander 	return set_pin(session, pin, pin_size, PKCS11_CKU_USER);
1117e8dbd92cSJens Wiklander }
11181dbb91e7SJens Wiklander 
11194daf39b3SJens Wiklander static enum pkcs11_rc check_so_pin(struct pkcs11_session *session,
11201dbb91e7SJens Wiklander 				   uint8_t *pin, size_t pin_size)
11211dbb91e7SJens Wiklander {
11221dbb91e7SJens Wiklander 	struct ck_token *token = session->token;
11231dbb91e7SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
11241dbb91e7SJens Wiklander 
11251dbb91e7SJens Wiklander 	assert(token->db_main->flags & PKCS11_CKFT_TOKEN_INITIALIZED);
11261dbb91e7SJens Wiklander 
11271a27b197SVesa Jääskeläinen 	if (IS_ENABLED(CFG_PKCS11_TA_AUTH_TEE_IDENTITY) &&
11281a27b197SVesa Jääskeläinen 	    token->db_main->flags & PKCS11_CKFT_PROTECTED_AUTHENTICATION_PATH)
11291a27b197SVesa Jääskeläinen 		return verify_identity_auth(token, PKCS11_CKU_SO);
11301a27b197SVesa Jääskeläinen 
11311dbb91e7SJens Wiklander 	if (token->db_main->flags & PKCS11_CKFT_SO_PIN_LOCKED)
11321dbb91e7SJens Wiklander 		return PKCS11_CKR_PIN_LOCKED;
11331dbb91e7SJens Wiklander 
11341dbb91e7SJens Wiklander 	rc = verify_pin(PKCS11_CKU_SO, pin, pin_size,
11351dbb91e7SJens Wiklander 			token->db_main->so_pin_salt,
11361dbb91e7SJens Wiklander 			token->db_main->so_pin_hash);
11371dbb91e7SJens Wiklander 	if (rc) {
11381dbb91e7SJens Wiklander 		unsigned int pin_count = 0;
11391dbb91e7SJens Wiklander 
11401dbb91e7SJens Wiklander 		if (rc != PKCS11_CKR_PIN_INCORRECT)
11411dbb91e7SJens Wiklander 			return rc;
11421dbb91e7SJens Wiklander 
11431dbb91e7SJens Wiklander 		token->db_main->flags |= PKCS11_CKFT_SO_PIN_COUNT_LOW;
11441dbb91e7SJens Wiklander 		token->db_main->so_pin_count++;
11451dbb91e7SJens Wiklander 
11461dbb91e7SJens Wiklander 		pin_count = token->db_main->so_pin_count;
11471dbb91e7SJens Wiklander 		if (pin_count == PKCS11_TOKEN_SO_PIN_COUNT_MAX - 1)
11481dbb91e7SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_SO_PIN_FINAL_TRY;
11491dbb91e7SJens Wiklander 		if (pin_count == PKCS11_TOKEN_SO_PIN_COUNT_MAX)
11501dbb91e7SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_SO_PIN_LOCKED;
11511dbb91e7SJens Wiklander 
11521dbb91e7SJens Wiklander 		update_persistent_db(token);
11531dbb91e7SJens Wiklander 
11541dbb91e7SJens Wiklander 		if (token->db_main->flags & PKCS11_CKFT_SO_PIN_LOCKED)
11551dbb91e7SJens Wiklander 			return PKCS11_CKR_PIN_LOCKED;
11561dbb91e7SJens Wiklander 
11571dbb91e7SJens Wiklander 		return PKCS11_CKR_PIN_INCORRECT;
11581dbb91e7SJens Wiklander 	}
11591dbb91e7SJens Wiklander 
11601dbb91e7SJens Wiklander 	if (token->db_main->so_pin_count) {
11611dbb91e7SJens Wiklander 		token->db_main->so_pin_count = 0;
11621dbb91e7SJens Wiklander 
11631dbb91e7SJens Wiklander 		update_persistent_db(token);
11641dbb91e7SJens Wiklander 	}
11651dbb91e7SJens Wiklander 
11661dbb91e7SJens Wiklander 	if (token->db_main->flags & (PKCS11_CKFT_SO_PIN_COUNT_LOW |
11671dbb91e7SJens Wiklander 				     PKCS11_CKFT_SO_PIN_FINAL_TRY)) {
11681dbb91e7SJens Wiklander 		token->db_main->flags &= ~(PKCS11_CKFT_SO_PIN_COUNT_LOW |
11691dbb91e7SJens Wiklander 					   PKCS11_CKFT_SO_PIN_FINAL_TRY);
11701dbb91e7SJens Wiklander 
11711dbb91e7SJens Wiklander 		update_persistent_db(token);
11721dbb91e7SJens Wiklander 	}
11731dbb91e7SJens Wiklander 
11741dbb91e7SJens Wiklander 	return PKCS11_CKR_OK;
11751dbb91e7SJens Wiklander }
11761dbb91e7SJens Wiklander 
11774daf39b3SJens Wiklander static enum pkcs11_rc check_user_pin(struct pkcs11_session *session,
11781dbb91e7SJens Wiklander 				     uint8_t *pin, size_t pin_size)
11791dbb91e7SJens Wiklander {
11801dbb91e7SJens Wiklander 	struct ck_token *token = session->token;
11811dbb91e7SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
11821dbb91e7SJens Wiklander 
11831a27b197SVesa Jääskeläinen 	if (IS_ENABLED(CFG_PKCS11_TA_AUTH_TEE_IDENTITY) &&
11841a27b197SVesa Jääskeläinen 	    token->db_main->flags & PKCS11_CKFT_PROTECTED_AUTHENTICATION_PATH)
11851a27b197SVesa Jääskeläinen 		return verify_identity_auth(token, PKCS11_CKU_USER);
11861a27b197SVesa Jääskeläinen 
11871dbb91e7SJens Wiklander 	if (!token->db_main->user_pin_salt)
11881dbb91e7SJens Wiklander 		return PKCS11_CKR_USER_PIN_NOT_INITIALIZED;
11891dbb91e7SJens Wiklander 
11901dbb91e7SJens Wiklander 	if (token->db_main->flags & PKCS11_CKFT_USER_PIN_LOCKED)
11911dbb91e7SJens Wiklander 		return PKCS11_CKR_PIN_LOCKED;
11921dbb91e7SJens Wiklander 
11931dbb91e7SJens Wiklander 	rc = verify_pin(PKCS11_CKU_USER, pin, pin_size,
11941dbb91e7SJens Wiklander 			token->db_main->user_pin_salt,
11951dbb91e7SJens Wiklander 			token->db_main->user_pin_hash);
11961dbb91e7SJens Wiklander 	if (rc) {
11971dbb91e7SJens Wiklander 		unsigned int pin_count = 0;
11981dbb91e7SJens Wiklander 
11991dbb91e7SJens Wiklander 		if (rc != PKCS11_CKR_PIN_INCORRECT)
12001dbb91e7SJens Wiklander 			return rc;
12011dbb91e7SJens Wiklander 
12021dbb91e7SJens Wiklander 		token->db_main->flags |= PKCS11_CKFT_USER_PIN_COUNT_LOW;
12031dbb91e7SJens Wiklander 		token->db_main->user_pin_count++;
12041dbb91e7SJens Wiklander 
12051dbb91e7SJens Wiklander 		pin_count = token->db_main->user_pin_count;
12061dbb91e7SJens Wiklander 		if (pin_count == PKCS11_TOKEN_USER_PIN_COUNT_MAX - 1)
12071dbb91e7SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_USER_PIN_FINAL_TRY;
12081dbb91e7SJens Wiklander 		if (pin_count == PKCS11_TOKEN_USER_PIN_COUNT_MAX)
12091dbb91e7SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_USER_PIN_LOCKED;
12101dbb91e7SJens Wiklander 
12111dbb91e7SJens Wiklander 		update_persistent_db(token);
12121dbb91e7SJens Wiklander 
12131dbb91e7SJens Wiklander 		if (token->db_main->flags & PKCS11_CKFT_USER_PIN_LOCKED)
12141dbb91e7SJens Wiklander 			return PKCS11_CKR_PIN_LOCKED;
12151dbb91e7SJens Wiklander 
12161dbb91e7SJens Wiklander 		return PKCS11_CKR_PIN_INCORRECT;
12171dbb91e7SJens Wiklander 	}
12181dbb91e7SJens Wiklander 
12191dbb91e7SJens Wiklander 	if (token->db_main->user_pin_count) {
12201dbb91e7SJens Wiklander 		token->db_main->user_pin_count = 0;
12211dbb91e7SJens Wiklander 
12221dbb91e7SJens Wiklander 		update_persistent_db(token);
12231dbb91e7SJens Wiklander 	}
12241dbb91e7SJens Wiklander 
12251dbb91e7SJens Wiklander 	if (token->db_main->flags & (PKCS11_CKFT_USER_PIN_COUNT_LOW |
12261dbb91e7SJens Wiklander 				     PKCS11_CKFT_USER_PIN_FINAL_TRY)) {
12271dbb91e7SJens Wiklander 		token->db_main->flags &= ~(PKCS11_CKFT_USER_PIN_COUNT_LOW |
12281dbb91e7SJens Wiklander 					   PKCS11_CKFT_USER_PIN_FINAL_TRY);
12291dbb91e7SJens Wiklander 
12301dbb91e7SJens Wiklander 		update_persistent_db(token);
12311dbb91e7SJens Wiklander 	}
12321dbb91e7SJens Wiklander 
12331dbb91e7SJens Wiklander 	return PKCS11_CKR_OK;
12341dbb91e7SJens Wiklander }
12351dbb91e7SJens Wiklander 
12364daf39b3SJens Wiklander enum pkcs11_rc entry_ck_set_pin(struct pkcs11_client *client,
12371dbb91e7SJens Wiklander 				uint32_t ptypes, TEE_Param *params)
12381dbb91e7SJens Wiklander {
12391dbb91e7SJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
12401dbb91e7SJens Wiklander 						TEE_PARAM_TYPE_NONE,
12411dbb91e7SJens Wiklander 						TEE_PARAM_TYPE_NONE,
12421dbb91e7SJens Wiklander 						TEE_PARAM_TYPE_NONE);
12431dbb91e7SJens Wiklander 	struct pkcs11_session *session = NULL;
12441dbb91e7SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
12451dbb91e7SJens Wiklander 	struct serialargs ctrlargs = { };
12461dbb91e7SJens Wiklander 	uint32_t old_pin_size = 0;
12471dbb91e7SJens Wiklander 	TEE_Param *ctrl = params;
12481dbb91e7SJens Wiklander 	uint32_t pin_size = 0;
12491dbb91e7SJens Wiklander 	void *old_pin = NULL;
12501dbb91e7SJens Wiklander 	void *pin = NULL;
12511dbb91e7SJens Wiklander 
12521dbb91e7SJens Wiklander 	if (!client || ptypes != exp_pt)
12531dbb91e7SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
12541dbb91e7SJens Wiklander 
12551dbb91e7SJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
12561dbb91e7SJens Wiklander 
1257f40f331fSEtienne Carriere 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
12581dbb91e7SJens Wiklander 	if (rc)
12591dbb91e7SJens Wiklander 		return rc;
12601dbb91e7SJens Wiklander 
12611dbb91e7SJens Wiklander 	rc = serialargs_get(&ctrlargs, &old_pin_size, sizeof(uint32_t));
12621dbb91e7SJens Wiklander 	if (rc)
12631dbb91e7SJens Wiklander 		return rc;
12641dbb91e7SJens Wiklander 
12651dbb91e7SJens Wiklander 	rc = serialargs_get(&ctrlargs, &pin_size, sizeof(uint32_t));
12661dbb91e7SJens Wiklander 	if (rc)
12671dbb91e7SJens Wiklander 		return rc;
12681dbb91e7SJens Wiklander 
12691dbb91e7SJens Wiklander 	rc = serialargs_get_ptr(&ctrlargs, &old_pin, old_pin_size);
12701dbb91e7SJens Wiklander 	if (rc)
12711dbb91e7SJens Wiklander 		return rc;
12721dbb91e7SJens Wiklander 
12731dbb91e7SJens Wiklander 	rc = serialargs_get_ptr(&ctrlargs, &pin, pin_size);
12741dbb91e7SJens Wiklander 	if (rc)
12751dbb91e7SJens Wiklander 		return rc;
12761dbb91e7SJens Wiklander 
12771dbb91e7SJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs))
12781dbb91e7SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
12791dbb91e7SJens Wiklander 
12801dbb91e7SJens Wiklander 	if (!pkcs11_session_is_read_write(session))
12811dbb91e7SJens Wiklander 		return PKCS11_CKR_SESSION_READ_ONLY;
12821dbb91e7SJens Wiklander 
12831dbb91e7SJens Wiklander 	if (pkcs11_session_is_so(session)) {
12841dbb91e7SJens Wiklander 		if (!(session->token->db_main->flags &
12851dbb91e7SJens Wiklander 		      PKCS11_CKFT_TOKEN_INITIALIZED))
12861dbb91e7SJens Wiklander 			return PKCS11_CKR_GENERAL_ERROR;
12871dbb91e7SJens Wiklander 
12881dbb91e7SJens Wiklander 		rc = check_so_pin(session, old_pin, old_pin_size);
12891dbb91e7SJens Wiklander 		if (rc)
12901dbb91e7SJens Wiklander 			return rc;
12911dbb91e7SJens Wiklander 
1292f40f331fSEtienne Carriere 		IMSG("PKCS11 session %"PRIu32": set PIN", session->handle);
12931dbb91e7SJens Wiklander 
12941dbb91e7SJens Wiklander 		return set_pin(session, pin, pin_size, PKCS11_CKU_SO);
12951dbb91e7SJens Wiklander 	}
12961dbb91e7SJens Wiklander 
12971dbb91e7SJens Wiklander 	if (!(session->token->db_main->flags &
12981dbb91e7SJens Wiklander 	      PKCS11_CKFT_USER_PIN_INITIALIZED))
12991dbb91e7SJens Wiklander 		return PKCS11_CKR_GENERAL_ERROR;
13001dbb91e7SJens Wiklander 
13011dbb91e7SJens Wiklander 	rc = check_user_pin(session, old_pin, old_pin_size);
13021dbb91e7SJens Wiklander 	if (rc)
13031dbb91e7SJens Wiklander 		return rc;
13041dbb91e7SJens Wiklander 
1305f40f331fSEtienne Carriere 	IMSG("PKCS11 session %"PRIu32": set PIN", session->handle);
13061dbb91e7SJens Wiklander 
13071dbb91e7SJens Wiklander 	return set_pin(session, pin, pin_size, PKCS11_CKU_USER);
13081dbb91e7SJens Wiklander }
1309f7cc36c0SJens Wiklander 
1310f7cc36c0SJens Wiklander static void session_login_user(struct pkcs11_session *session)
1311f7cc36c0SJens Wiklander {
1312f7cc36c0SJens Wiklander 	struct pkcs11_client *client = session->client;
1313f7cc36c0SJens Wiklander 	struct pkcs11_session *sess = NULL;
1314f7cc36c0SJens Wiklander 
1315f7cc36c0SJens Wiklander 	TAILQ_FOREACH(sess, &client->session_list, link) {
1316f7cc36c0SJens Wiklander 		if (sess->token != session->token)
1317f7cc36c0SJens Wiklander 			continue;
1318f7cc36c0SJens Wiklander 
1319f7cc36c0SJens Wiklander 		if (pkcs11_session_is_read_write(sess))
1320f7cc36c0SJens Wiklander 			sess->state = PKCS11_CKS_RW_USER_FUNCTIONS;
1321f7cc36c0SJens Wiklander 		else
1322f7cc36c0SJens Wiklander 			sess->state = PKCS11_CKS_RO_USER_FUNCTIONS;
1323f7cc36c0SJens Wiklander 	}
1324f7cc36c0SJens Wiklander }
1325f7cc36c0SJens Wiklander 
1326f7cc36c0SJens Wiklander static void session_login_so(struct pkcs11_session *session)
1327f7cc36c0SJens Wiklander {
1328f7cc36c0SJens Wiklander 	struct pkcs11_client *client = session->client;
1329f7cc36c0SJens Wiklander 	struct pkcs11_session *sess = NULL;
1330f7cc36c0SJens Wiklander 
1331f7cc36c0SJens Wiklander 	TAILQ_FOREACH(sess, &client->session_list, link) {
1332f7cc36c0SJens Wiklander 		if (sess->token != session->token)
1333f7cc36c0SJens Wiklander 			continue;
1334f7cc36c0SJens Wiklander 
1335f7cc36c0SJens Wiklander 		if (pkcs11_session_is_read_write(sess))
1336f7cc36c0SJens Wiklander 			sess->state = PKCS11_CKS_RW_SO_FUNCTIONS;
1337f7cc36c0SJens Wiklander 		else
1338f7cc36c0SJens Wiklander 			TEE_Panic(0);
1339f7cc36c0SJens Wiklander 	}
1340f7cc36c0SJens Wiklander }
1341f7cc36c0SJens Wiklander 
1342f7cc36c0SJens Wiklander static void session_logout(struct pkcs11_session *session)
1343f7cc36c0SJens Wiklander {
1344f7cc36c0SJens Wiklander 	struct pkcs11_client *client = session->client;
1345f7cc36c0SJens Wiklander 	struct pkcs11_session *sess = NULL;
1346f7cc36c0SJens Wiklander 
1347f7cc36c0SJens Wiklander 	TAILQ_FOREACH(sess, &client->session_list, link) {
134889735787SRuchika Gupta 		struct pkcs11_object *obj = NULL;
13493bf0e097SRuchika Gupta 		struct pkcs11_object *tobj = NULL;
135089735787SRuchika Gupta 		uint32_t handle = 0;
135189735787SRuchika Gupta 
1352f7cc36c0SJens Wiklander 		if (sess->token != session->token)
1353f7cc36c0SJens Wiklander 			continue;
1354f7cc36c0SJens Wiklander 
135589735787SRuchika Gupta 		release_active_processing(session);
135689735787SRuchika Gupta 
135789735787SRuchika Gupta 		/* Destroy private session objects */
13583bf0e097SRuchika Gupta 		LIST_FOREACH_SAFE(obj, &sess->object_list, link, tobj) {
135989735787SRuchika Gupta 			if (object_is_private(obj->attributes))
136089735787SRuchika Gupta 				destroy_object(sess, obj, true);
136189735787SRuchika Gupta 		}
136289735787SRuchika Gupta 
136389735787SRuchika Gupta 		/*
136489735787SRuchika Gupta 		 * Remove handle of token private objects from
136589735787SRuchika Gupta 		 * sessions object_handle_db
136689735787SRuchika Gupta 		 */
136789735787SRuchika Gupta 		LIST_FOREACH(obj, &session->token->object_list, link) {
136889735787SRuchika Gupta 			handle = pkcs11_object2handle(obj, session);
136989735787SRuchika Gupta 
137089735787SRuchika Gupta 			if (handle && object_is_private(obj->attributes))
1371bc555ee0SVesa Jääskeläinen 				handle_put(get_object_handle_db(sess), handle);
137289735787SRuchika Gupta 		}
137389735787SRuchika Gupta 
137489735787SRuchika Gupta 		release_session_find_obj_context(session);
137589735787SRuchika Gupta 
1376f7cc36c0SJens Wiklander 		if (pkcs11_session_is_read_write(sess))
1377f7cc36c0SJens Wiklander 			sess->state = PKCS11_CKS_RW_PUBLIC_SESSION;
1378f7cc36c0SJens Wiklander 		else
1379f7cc36c0SJens Wiklander 			sess->state = PKCS11_CKS_RO_PUBLIC_SESSION;
1380f7cc36c0SJens Wiklander 	}
1381f7cc36c0SJens Wiklander }
1382f7cc36c0SJens Wiklander 
13834daf39b3SJens Wiklander enum pkcs11_rc entry_ck_login(struct pkcs11_client *client,
1384f7cc36c0SJens Wiklander 			      uint32_t ptypes, TEE_Param *params)
1385f7cc36c0SJens Wiklander {
1386f7cc36c0SJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
1387f7cc36c0SJens Wiklander 						TEE_PARAM_TYPE_NONE,
1388f7cc36c0SJens Wiklander 						TEE_PARAM_TYPE_NONE,
1389f7cc36c0SJens Wiklander 						TEE_PARAM_TYPE_NONE);
1390f7cc36c0SJens Wiklander 	struct pkcs11_session *session = NULL;
1391f7cc36c0SJens Wiklander 	struct pkcs11_session *sess = NULL;
1392f7cc36c0SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
1393f7cc36c0SJens Wiklander 	struct serialargs ctrlargs = { };
1394f7cc36c0SJens Wiklander 	TEE_Param *ctrl = params;
1395f7cc36c0SJens Wiklander 	uint32_t user_type = 0;
1396f7cc36c0SJens Wiklander 	uint32_t pin_size = 0;
1397f7cc36c0SJens Wiklander 	void *pin = NULL;
1398f7cc36c0SJens Wiklander 
1399f7cc36c0SJens Wiklander 	if (!client || ptypes != exp_pt)
1400f7cc36c0SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
1401f7cc36c0SJens Wiklander 
1402f7cc36c0SJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
1403f7cc36c0SJens Wiklander 
1404f40f331fSEtienne Carriere 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
1405f7cc36c0SJens Wiklander 	if (rc)
1406f7cc36c0SJens Wiklander 		return rc;
1407f7cc36c0SJens Wiklander 
1408f7cc36c0SJens Wiklander 	rc = serialargs_get(&ctrlargs, &user_type, sizeof(uint32_t));
1409f7cc36c0SJens Wiklander 	if (rc)
1410f7cc36c0SJens Wiklander 		return rc;
1411f7cc36c0SJens Wiklander 
1412f7cc36c0SJens Wiklander 	rc = serialargs_get(&ctrlargs, &pin_size, sizeof(uint32_t));
1413f7cc36c0SJens Wiklander 	if (rc)
1414f7cc36c0SJens Wiklander 		return rc;
1415f7cc36c0SJens Wiklander 
1416f7cc36c0SJens Wiklander 	rc = serialargs_get_ptr(&ctrlargs, &pin, pin_size);
1417f7cc36c0SJens Wiklander 	if (rc)
1418f7cc36c0SJens Wiklander 		return rc;
1419f7cc36c0SJens Wiklander 
1420f7cc36c0SJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs))
1421f7cc36c0SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
1422f7cc36c0SJens Wiklander 
1423f7cc36c0SJens Wiklander 	switch (user_type) {
1424f7cc36c0SJens Wiklander 	case PKCS11_CKU_SO:
1425f7cc36c0SJens Wiklander 		if (pkcs11_session_is_so(session))
1426f7cc36c0SJens Wiklander 			return PKCS11_CKR_USER_ALREADY_LOGGED_IN;
1427f7cc36c0SJens Wiklander 
1428f7cc36c0SJens Wiklander 		if (pkcs11_session_is_user(session))
1429f7cc36c0SJens Wiklander 			return PKCS11_CKR_USER_ANOTHER_ALREADY_LOGGED_IN;
1430f7cc36c0SJens Wiklander 
1431f7cc36c0SJens Wiklander 		TAILQ_FOREACH(sess, &client->session_list, link)
1432f7cc36c0SJens Wiklander 			if (sess->token == session->token &&
1433f7cc36c0SJens Wiklander 			    !pkcs11_session_is_read_write(sess))
1434f7cc36c0SJens Wiklander 				return PKCS11_CKR_SESSION_READ_ONLY_EXISTS;
1435f7cc36c0SJens Wiklander 
1436f7cc36c0SJens Wiklander 		/*
1437f7cc36c0SJens Wiklander 		 * This is the point where we could check if another client
1438f7cc36c0SJens Wiklander 		 * has another user or SO logged in.
1439f7cc36c0SJens Wiklander 		 *
1440f7cc36c0SJens Wiklander 		 * The spec says:
1441f7cc36c0SJens Wiklander 		 * CKR_USER_TOO_MANY_TYPES: An attempt was made to have
1442f7cc36c0SJens Wiklander 		 * more distinct users simultaneously logged into the token
1443f7cc36c0SJens Wiklander 		 * than the token and/or library permits. For example, if
1444f7cc36c0SJens Wiklander 		 * some application has an open SO session, and another
1445f7cc36c0SJens Wiklander 		 * application attempts to log the normal user into a
1446f7cc36c0SJens Wiklander 		 * session, the attempt may return this error. It is not
1447f7cc36c0SJens Wiklander 		 * required to, however. Only if the simultaneous distinct
1448f7cc36c0SJens Wiklander 		 * users cannot be supported does C_Login have to return
1449f7cc36c0SJens Wiklander 		 * this value. Note that this error code generalizes to
1450f7cc36c0SJens Wiklander 		 * true multi-user tokens.
1451f7cc36c0SJens Wiklander 		 *
1452f7cc36c0SJens Wiklander 		 * So it's permitted to have another user or SO logged in
1453f7cc36c0SJens Wiklander 		 * from another client.
1454f7cc36c0SJens Wiklander 		 */
1455f7cc36c0SJens Wiklander 
1456f7cc36c0SJens Wiklander 		rc = check_so_pin(session, pin, pin_size);
1457f7cc36c0SJens Wiklander 		if (!rc)
1458f7cc36c0SJens Wiklander 			session_login_so(session);
1459f7cc36c0SJens Wiklander 
1460f7cc36c0SJens Wiklander 		break;
1461f7cc36c0SJens Wiklander 
1462f7cc36c0SJens Wiklander 	case PKCS11_CKU_USER:
1463f7cc36c0SJens Wiklander 		if (pkcs11_session_is_so(session))
1464f7cc36c0SJens Wiklander 			return PKCS11_CKR_USER_ANOTHER_ALREADY_LOGGED_IN;
1465f7cc36c0SJens Wiklander 
1466f7cc36c0SJens Wiklander 		if (pkcs11_session_is_user(session))
1467f7cc36c0SJens Wiklander 			return PKCS11_CKR_USER_ALREADY_LOGGED_IN;
1468f7cc36c0SJens Wiklander 
1469f7cc36c0SJens Wiklander 		/*
1470f7cc36c0SJens Wiklander 		 * This is the point where we could check if another client
1471f7cc36c0SJens Wiklander 		 * has another user or SO logged in.
1472f7cc36c0SJens Wiklander 		 * See comment on CKR_USER_TOO_MANY_TYPES above.
1473f7cc36c0SJens Wiklander 		 */
1474f7cc36c0SJens Wiklander 
1475f7cc36c0SJens Wiklander 		rc = check_user_pin(session, pin, pin_size);
1476f7cc36c0SJens Wiklander 		if (!rc)
1477f7cc36c0SJens Wiklander 			session_login_user(session);
1478f7cc36c0SJens Wiklander 
1479f7cc36c0SJens Wiklander 		break;
1480f7cc36c0SJens Wiklander 
1481f7cc36c0SJens Wiklander 	case PKCS11_CKU_CONTEXT_SPECIFIC:
1482f7cc36c0SJens Wiklander 		return PKCS11_CKR_OPERATION_NOT_INITIALIZED;
1483f7cc36c0SJens Wiklander 
1484f7cc36c0SJens Wiklander 	default:
1485f7cc36c0SJens Wiklander 		return PKCS11_CKR_USER_TYPE_INVALID;
1486f7cc36c0SJens Wiklander 	}
1487f7cc36c0SJens Wiklander 
1488f7cc36c0SJens Wiklander 	if (!rc)
1489f40f331fSEtienne Carriere 		IMSG("PKCS11 session %"PRIu32": login", session->handle);
1490f7cc36c0SJens Wiklander 
1491f7cc36c0SJens Wiklander 	return rc;
1492f7cc36c0SJens Wiklander }
1493f7cc36c0SJens Wiklander 
14944daf39b3SJens Wiklander enum pkcs11_rc entry_ck_logout(struct pkcs11_client *client,
1495f7cc36c0SJens Wiklander 			       uint32_t ptypes, TEE_Param *params)
1496f7cc36c0SJens Wiklander {
1497f7cc36c0SJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
1498f7cc36c0SJens Wiklander 						TEE_PARAM_TYPE_NONE,
1499f7cc36c0SJens Wiklander 						TEE_PARAM_TYPE_NONE,
1500f7cc36c0SJens Wiklander 						TEE_PARAM_TYPE_NONE);
1501f7cc36c0SJens Wiklander 	struct pkcs11_session *session = NULL;
1502f7cc36c0SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
1503f7cc36c0SJens Wiklander 	struct serialargs ctrlargs = { };
1504f7cc36c0SJens Wiklander 	TEE_Param *ctrl = params;
1505f7cc36c0SJens Wiklander 
1506f7cc36c0SJens Wiklander 	if (!client || ptypes != exp_pt)
1507f7cc36c0SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
1508f7cc36c0SJens Wiklander 
1509f7cc36c0SJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
1510f7cc36c0SJens Wiklander 
1511f40f331fSEtienne Carriere 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
1512f7cc36c0SJens Wiklander 	if (rc)
1513f7cc36c0SJens Wiklander 		return rc;
1514f7cc36c0SJens Wiklander 
1515f7cc36c0SJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs))
1516f7cc36c0SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
1517f7cc36c0SJens Wiklander 
1518f7cc36c0SJens Wiklander 	if (pkcs11_session_is_public(session))
1519f7cc36c0SJens Wiklander 		return PKCS11_CKR_USER_NOT_LOGGED_IN;
1520f7cc36c0SJens Wiklander 
1521f7cc36c0SJens Wiklander 	session_logout(session);
1522f7cc36c0SJens Wiklander 
1523f40f331fSEtienne Carriere 	IMSG("PKCS11 session %"PRIu32": logout", session->handle);
1524f7cc36c0SJens Wiklander 
1525f7cc36c0SJens Wiklander 	return PKCS11_CKR_OK;
1526f7cc36c0SJens Wiklander }
152722587dc4SVesa Jääskeläinen 
152822587dc4SVesa Jääskeläinen static TEE_Result seed_rng_pool(void *seed, size_t length)
152922587dc4SVesa Jääskeläinen {
153022587dc4SVesa Jääskeläinen 	static const TEE_UUID system_uuid = PTA_SYSTEM_UUID;
153122587dc4SVesa Jääskeläinen 	uint32_t param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
153222587dc4SVesa Jääskeläinen 					       TEE_PARAM_TYPE_NONE,
153322587dc4SVesa Jääskeläinen 					       TEE_PARAM_TYPE_NONE,
153422587dc4SVesa Jääskeläinen 					       TEE_PARAM_TYPE_NONE);
153522587dc4SVesa Jääskeläinen 	TEE_Param params[TEE_NUM_PARAMS] = { };
153622587dc4SVesa Jääskeläinen 	TEE_TASessionHandle sess = TEE_HANDLE_NULL;
153722587dc4SVesa Jääskeläinen 	TEE_Result res = TEE_ERROR_GENERIC;
153822587dc4SVesa Jääskeläinen 	uint32_t ret_orig = 0;
153922587dc4SVesa Jääskeläinen 
154022587dc4SVesa Jääskeläinen 	params[0].memref.buffer = seed;
154122587dc4SVesa Jääskeläinen 	params[0].memref.size = (uint32_t)length;
154222587dc4SVesa Jääskeläinen 
154322587dc4SVesa Jääskeläinen 	res = TEE_OpenTASession(&system_uuid, TEE_TIMEOUT_INFINITE, 0, NULL,
154422587dc4SVesa Jääskeläinen 				&sess, &ret_orig);
154522587dc4SVesa Jääskeläinen 	if (res != TEE_SUCCESS) {
154622587dc4SVesa Jääskeläinen 		EMSG("Can't open session to system PTA");
154722587dc4SVesa Jääskeläinen 		return res;
154822587dc4SVesa Jääskeläinen 	}
154922587dc4SVesa Jääskeläinen 
155022587dc4SVesa Jääskeläinen 	res = TEE_InvokeTACommand(sess, TEE_TIMEOUT_INFINITE,
155122587dc4SVesa Jääskeläinen 				  PTA_SYSTEM_ADD_RNG_ENTROPY,
155222587dc4SVesa Jääskeläinen 				  param_types, params, &ret_orig);
155322587dc4SVesa Jääskeläinen 	if (res != TEE_SUCCESS)
155422587dc4SVesa Jääskeläinen 		EMSG("Can't invoke system PTA");
155522587dc4SVesa Jääskeläinen 
155622587dc4SVesa Jääskeläinen 	TEE_CloseTASession(sess);
155722587dc4SVesa Jääskeläinen 	return res;
155822587dc4SVesa Jääskeläinen }
155922587dc4SVesa Jääskeläinen 
156022587dc4SVesa Jääskeläinen enum pkcs11_rc entry_ck_seed_random(struct pkcs11_client *client,
156122587dc4SVesa Jääskeläinen 				    uint32_t ptypes, TEE_Param *params)
156222587dc4SVesa Jääskeläinen {
156322587dc4SVesa Jääskeläinen 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
156422587dc4SVesa Jääskeläinen 						TEE_PARAM_TYPE_MEMREF_INPUT,
156522587dc4SVesa Jääskeläinen 						TEE_PARAM_TYPE_NONE,
156622587dc4SVesa Jääskeläinen 						TEE_PARAM_TYPE_NONE);
156722587dc4SVesa Jääskeläinen 	TEE_Param *ctrl = params;
156822587dc4SVesa Jääskeläinen 	TEE_Param *in = params + 1;
156922587dc4SVesa Jääskeläinen 	enum pkcs11_rc rc = PKCS11_CKR_OK;
157022587dc4SVesa Jääskeläinen 	struct serialargs ctrlargs = { };
157122587dc4SVesa Jääskeläinen 	struct pkcs11_session *session = NULL;
157222587dc4SVesa Jääskeläinen 	TEE_Result res = TEE_SUCCESS;
157322587dc4SVesa Jääskeläinen 
157422587dc4SVesa Jääskeläinen 	if (!client || ptypes != exp_pt)
157522587dc4SVesa Jääskeläinen 		return PKCS11_CKR_ARGUMENTS_BAD;
157622587dc4SVesa Jääskeläinen 
157722587dc4SVesa Jääskeläinen 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
157822587dc4SVesa Jääskeläinen 
157922587dc4SVesa Jääskeläinen 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
158022587dc4SVesa Jääskeläinen 	if (rc)
158122587dc4SVesa Jääskeläinen 		return rc;
158222587dc4SVesa Jääskeläinen 
158322587dc4SVesa Jääskeläinen 	if (serialargs_remaining_bytes(&ctrlargs))
158422587dc4SVesa Jääskeläinen 		return PKCS11_CKR_ARGUMENTS_BAD;
158522587dc4SVesa Jääskeläinen 
158622587dc4SVesa Jääskeläinen 	if (in->memref.size && !in->memref.buffer)
158722587dc4SVesa Jääskeläinen 		return PKCS11_CKR_ARGUMENTS_BAD;
158822587dc4SVesa Jääskeläinen 
158922587dc4SVesa Jääskeläinen 	if (!in->memref.size)
159022587dc4SVesa Jääskeläinen 		return PKCS11_CKR_OK;
159122587dc4SVesa Jääskeläinen 
159222587dc4SVesa Jääskeläinen 	res = seed_rng_pool(in->memref.buffer, in->memref.size);
159322587dc4SVesa Jääskeläinen 	if (res != TEE_SUCCESS)
159422587dc4SVesa Jääskeläinen 		return PKCS11_CKR_FUNCTION_FAILED;
159522587dc4SVesa Jääskeläinen 
159622587dc4SVesa Jääskeläinen 	DMSG("PKCS11 session %"PRIu32": seed random", session->handle);
159722587dc4SVesa Jääskeläinen 
159822587dc4SVesa Jääskeläinen 	return PKCS11_CKR_OK;
159922587dc4SVesa Jääskeläinen }
160022587dc4SVesa Jääskeläinen 
160122587dc4SVesa Jääskeläinen enum pkcs11_rc entry_ck_generate_random(struct pkcs11_client *client,
160222587dc4SVesa Jääskeläinen 					uint32_t ptypes, TEE_Param *params)
160322587dc4SVesa Jääskeläinen {
160422587dc4SVesa Jääskeläinen 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
160522587dc4SVesa Jääskeläinen 						TEE_PARAM_TYPE_NONE,
160622587dc4SVesa Jääskeläinen 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
160722587dc4SVesa Jääskeläinen 						TEE_PARAM_TYPE_NONE);
160822587dc4SVesa Jääskeläinen 	TEE_Param *ctrl = params;
160922587dc4SVesa Jääskeläinen 	TEE_Param *out = params + 2;
161022587dc4SVesa Jääskeläinen 	enum pkcs11_rc rc = PKCS11_CKR_OK;
161122587dc4SVesa Jääskeläinen 	struct serialargs ctrlargs = { };
161222587dc4SVesa Jääskeläinen 	struct pkcs11_session *session = NULL;
161322587dc4SVesa Jääskeläinen 	void *buffer = NULL;
161422587dc4SVesa Jääskeläinen 	size_t buffer_size = 0;
161522587dc4SVesa Jääskeläinen 	uint8_t *data = NULL;
161622587dc4SVesa Jääskeläinen 	size_t left = 0;
161722587dc4SVesa Jääskeläinen 
161822587dc4SVesa Jääskeläinen 	if (!client || ptypes != exp_pt)
161922587dc4SVesa Jääskeläinen 		return PKCS11_CKR_ARGUMENTS_BAD;
162022587dc4SVesa Jääskeläinen 
162122587dc4SVesa Jääskeläinen 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
162222587dc4SVesa Jääskeläinen 
162322587dc4SVesa Jääskeläinen 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
162422587dc4SVesa Jääskeläinen 	if (rc)
162522587dc4SVesa Jääskeläinen 		return rc;
162622587dc4SVesa Jääskeläinen 
162722587dc4SVesa Jääskeläinen 	if (serialargs_remaining_bytes(&ctrlargs))
162822587dc4SVesa Jääskeläinen 		return PKCS11_CKR_ARGUMENTS_BAD;
162922587dc4SVesa Jääskeläinen 
163022587dc4SVesa Jääskeläinen 	if (out->memref.size && !out->memref.buffer)
163122587dc4SVesa Jääskeläinen 		return PKCS11_CKR_ARGUMENTS_BAD;
163222587dc4SVesa Jääskeläinen 
163322587dc4SVesa Jääskeläinen 	if (!out->memref.size)
163422587dc4SVesa Jääskeläinen 		return PKCS11_CKR_OK;
163522587dc4SVesa Jääskeläinen 
163622587dc4SVesa Jääskeläinen 	buffer_size = MIN(out->memref.size, RNG_CHUNK_SIZE);
163722587dc4SVesa Jääskeläinen 	buffer = TEE_Malloc(buffer_size, TEE_MALLOC_FILL_ZERO);
163822587dc4SVesa Jääskeläinen 	if (!buffer)
163922587dc4SVesa Jääskeläinen 		return PKCS11_CKR_DEVICE_MEMORY;
164022587dc4SVesa Jääskeläinen 
164122587dc4SVesa Jääskeläinen 	data = out->memref.buffer;
164222587dc4SVesa Jääskeläinen 	left = out->memref.size;
164322587dc4SVesa Jääskeläinen 
164422587dc4SVesa Jääskeläinen 	while (left) {
164522587dc4SVesa Jääskeläinen 		size_t count = MIN(left, buffer_size);
164622587dc4SVesa Jääskeläinen 
164722587dc4SVesa Jääskeläinen 		TEE_GenerateRandom(buffer, count);
164822587dc4SVesa Jääskeläinen 		TEE_MemMove(data, buffer, count);
164922587dc4SVesa Jääskeläinen 
165022587dc4SVesa Jääskeläinen 		data += count;
165122587dc4SVesa Jääskeläinen 		left -= count;
165222587dc4SVesa Jääskeläinen 	}
165322587dc4SVesa Jääskeläinen 
165422587dc4SVesa Jääskeläinen 	DMSG("PKCS11 session %"PRIu32": generate random", session->handle);
165522587dc4SVesa Jääskeläinen 
165622587dc4SVesa Jääskeläinen 	TEE_Free(buffer);
165722587dc4SVesa Jääskeläinen 
165822587dc4SVesa Jääskeläinen 	return PKCS11_CKR_OK;
165922587dc4SVesa Jääskeläinen }
1660