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 98*bb5d1825SEtienne Carriere void token_invalidate_object_handles(struct pkcs11_object *obj) 99*bb5d1825SEtienne Carriere { 100*bb5d1825SEtienne Carriere struct pkcs11_client *client = NULL; 101*bb5d1825SEtienne Carriere uint32_t handle = 0; 102*bb5d1825SEtienne Carriere 103*bb5d1825SEtienne Carriere TAILQ_FOREACH(client, &pkcs11_client_list, link) { 104*bb5d1825SEtienne Carriere handle = handle_lookup_handle(&client->object_handle_db, obj); 105*bb5d1825SEtienne Carriere if (handle) 106*bb5d1825SEtienne Carriere handle_invalidate(&client->object_handle_db, handle); 107*bb5d1825SEtienne Carriere } 108*bb5d1825SEtienne Carriere } 109*bb5d1825SEtienne Carriere 110e084583eSEtienne Carriere struct pkcs11_client *register_client(void) 111e084583eSEtienne Carriere { 112e084583eSEtienne Carriere struct pkcs11_client *client = NULL; 113e084583eSEtienne Carriere 114e084583eSEtienne Carriere client = TEE_Malloc(sizeof(*client), TEE_MALLOC_FILL_ZERO); 115e084583eSEtienne Carriere if (!client) 116e084583eSEtienne Carriere return NULL; 117e084583eSEtienne Carriere 118e084583eSEtienne Carriere TAILQ_INSERT_HEAD(&pkcs11_client_list, client, link); 119e084583eSEtienne Carriere TAILQ_INIT(&client->session_list); 120e084583eSEtienne Carriere handle_db_init(&client->session_handle_db); 121bc555ee0SVesa Jääskeläinen handle_db_init(&client->object_handle_db); 122e084583eSEtienne Carriere 123e084583eSEtienne Carriere return client; 124e084583eSEtienne Carriere } 125e084583eSEtienne Carriere 126e084583eSEtienne Carriere void unregister_client(struct pkcs11_client *client) 127e084583eSEtienne Carriere { 1286e4f8f17SEtienne Carriere struct pkcs11_session *session = NULL; 1296e4f8f17SEtienne Carriere struct pkcs11_session *next = NULL; 1306e4f8f17SEtienne Carriere 131e084583eSEtienne Carriere if (!client) { 132e084583eSEtienne Carriere EMSG("Invalid TEE session handle"); 133e084583eSEtienne Carriere return; 134e084583eSEtienne Carriere } 135e084583eSEtienne Carriere 1366e4f8f17SEtienne Carriere TAILQ_FOREACH_SAFE(session, &client->session_list, link, next) 1376e4f8f17SEtienne Carriere close_ck_session(session); 1386e4f8f17SEtienne Carriere 139e084583eSEtienne Carriere TAILQ_REMOVE(&pkcs11_client_list, client, link); 140bc555ee0SVesa Jääskeläinen handle_db_destroy(&client->object_handle_db); 141e084583eSEtienne Carriere handle_db_destroy(&client->session_handle_db); 142e084583eSEtienne Carriere TEE_Free(client); 143e084583eSEtienne Carriere } 144e084583eSEtienne Carriere 145c84ccd0aSEtienne Carriere static TEE_Result pkcs11_token_init(unsigned int id) 146c84ccd0aSEtienne Carriere { 147c84ccd0aSEtienne Carriere struct ck_token *token = init_persistent_db(id); 148c84ccd0aSEtienne Carriere 149c84ccd0aSEtienne Carriere if (!token) 150c84ccd0aSEtienne Carriere return TEE_ERROR_SECURITY; 151c84ccd0aSEtienne Carriere 152c84ccd0aSEtienne Carriere if (token->state == PKCS11_TOKEN_RESET) { 153c84ccd0aSEtienne Carriere /* As per PKCS#11 spec, token resets to read/write state */ 154c84ccd0aSEtienne Carriere token->state = PKCS11_TOKEN_READ_WRITE; 155c84ccd0aSEtienne Carriere token->session_count = 0; 156c84ccd0aSEtienne Carriere token->rw_session_count = 0; 157c84ccd0aSEtienne Carriere } 158c84ccd0aSEtienne Carriere 159c84ccd0aSEtienne Carriere return TEE_SUCCESS; 160c84ccd0aSEtienne Carriere } 161c84ccd0aSEtienne Carriere 162c84ccd0aSEtienne Carriere TEE_Result pkcs11_init(void) 163c84ccd0aSEtienne Carriere { 164c84ccd0aSEtienne Carriere unsigned int id = 0; 165c84ccd0aSEtienne Carriere TEE_Result ret = TEE_ERROR_GENERIC; 166c84ccd0aSEtienne Carriere 167c84ccd0aSEtienne Carriere for (id = 0; id < TOKEN_COUNT; id++) { 168c84ccd0aSEtienne Carriere ret = pkcs11_token_init(id); 169c84ccd0aSEtienne Carriere if (ret) 170e084583eSEtienne Carriere break; 171c84ccd0aSEtienne Carriere } 172c84ccd0aSEtienne Carriere 173c84ccd0aSEtienne Carriere return ret; 174c84ccd0aSEtienne Carriere } 175c84ccd0aSEtienne Carriere 176c84ccd0aSEtienne Carriere void pkcs11_deinit(void) 177c84ccd0aSEtienne Carriere { 178c84ccd0aSEtienne Carriere unsigned int id = 0; 179c84ccd0aSEtienne Carriere 180c84ccd0aSEtienne Carriere for (id = 0; id < TOKEN_COUNT; id++) 181c84ccd0aSEtienne Carriere close_persistent_db(get_token(id)); 182c84ccd0aSEtienne Carriere } 18322ac6984SEtienne Carriere 184512cbf1dSJens Wiklander /* 185512cbf1dSJens Wiklander * Currently no support for dual operations. 186512cbf1dSJens Wiklander */ 187512cbf1dSJens Wiklander enum pkcs11_rc set_processing_state(struct pkcs11_session *session, 188512cbf1dSJens Wiklander enum processing_func function, 189512cbf1dSJens Wiklander struct pkcs11_object *obj1, 190512cbf1dSJens Wiklander struct pkcs11_object *obj2) 191512cbf1dSJens Wiklander { 192512cbf1dSJens Wiklander enum pkcs11_proc_state state = PKCS11_SESSION_READY; 193512cbf1dSJens Wiklander struct active_processing *proc = NULL; 194512cbf1dSJens Wiklander 195512cbf1dSJens Wiklander if (session->processing) 196512cbf1dSJens Wiklander return PKCS11_CKR_OPERATION_ACTIVE; 197512cbf1dSJens Wiklander 198512cbf1dSJens Wiklander switch (function) { 199512cbf1dSJens Wiklander case PKCS11_FUNCTION_ENCRYPT: 200512cbf1dSJens Wiklander state = PKCS11_SESSION_ENCRYPTING; 201512cbf1dSJens Wiklander break; 202512cbf1dSJens Wiklander case PKCS11_FUNCTION_DECRYPT: 203512cbf1dSJens Wiklander state = PKCS11_SESSION_DECRYPTING; 204512cbf1dSJens Wiklander break; 205512cbf1dSJens Wiklander case PKCS11_FUNCTION_SIGN: 206512cbf1dSJens Wiklander state = PKCS11_SESSION_SIGNING; 207512cbf1dSJens Wiklander break; 208512cbf1dSJens Wiklander case PKCS11_FUNCTION_VERIFY: 209512cbf1dSJens Wiklander state = PKCS11_SESSION_VERIFYING; 210512cbf1dSJens Wiklander break; 211512cbf1dSJens Wiklander case PKCS11_FUNCTION_DIGEST: 212512cbf1dSJens Wiklander state = PKCS11_SESSION_DIGESTING; 213512cbf1dSJens Wiklander break; 214512cbf1dSJens Wiklander case PKCS11_FUNCTION_DERIVE: 2155f80f270SRuchika Gupta case PKCS11_FUNCTION_WRAP: 2165f80f270SRuchika Gupta case PKCS11_FUNCTION_UNWRAP: 2175f80f270SRuchika Gupta state = PKCS11_SESSION_BUSY; 218512cbf1dSJens Wiklander break; 219512cbf1dSJens Wiklander default: 220512cbf1dSJens Wiklander TEE_Panic(function); 221512cbf1dSJens Wiklander return -1; 222512cbf1dSJens Wiklander } 223512cbf1dSJens Wiklander 224512cbf1dSJens Wiklander proc = TEE_Malloc(sizeof(*proc), TEE_MALLOC_FILL_ZERO); 225512cbf1dSJens Wiklander if (!proc) 226512cbf1dSJens Wiklander return PKCS11_CKR_DEVICE_MEMORY; 227512cbf1dSJens Wiklander 228512cbf1dSJens Wiklander /* Boolean are default to false and pointers to NULL */ 229512cbf1dSJens Wiklander proc->state = state; 2302364aa69SRuchika Gupta proc->step = PKCS11_FUNC_STEP_INIT; 231512cbf1dSJens Wiklander proc->tee_op_handle = TEE_HANDLE_NULL; 232fb279d8bSVesa Jääskeläinen proc->tee_hash_algo = 0; 233fb279d8bSVesa Jääskeläinen proc->tee_hash_op_handle = TEE_HANDLE_NULL; 234512cbf1dSJens Wiklander 235512cbf1dSJens Wiklander if (obj1 && get_bool(obj1->attributes, PKCS11_CKA_ALWAYS_AUTHENTICATE)) 236512cbf1dSJens Wiklander proc->always_authen = true; 237512cbf1dSJens Wiklander 238512cbf1dSJens Wiklander if (obj2 && get_bool(obj2->attributes, PKCS11_CKA_ALWAYS_AUTHENTICATE)) 239512cbf1dSJens Wiklander proc->always_authen = true; 240512cbf1dSJens Wiklander 241512cbf1dSJens Wiklander session->processing = proc; 242512cbf1dSJens Wiklander 243512cbf1dSJens Wiklander return PKCS11_CKR_OK; 244512cbf1dSJens Wiklander } 245512cbf1dSJens Wiklander 2464daf39b3SJens Wiklander enum pkcs11_rc entry_ck_slot_list(uint32_t ptypes, TEE_Param *params) 24722ac6984SEtienne Carriere { 24822ac6984SEtienne Carriere const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 24922ac6984SEtienne Carriere TEE_PARAM_TYPE_NONE, 25022ac6984SEtienne Carriere TEE_PARAM_TYPE_MEMREF_OUTPUT, 25122ac6984SEtienne Carriere TEE_PARAM_TYPE_NONE); 25239b43b78SJens Wiklander TEE_Param *out = params + 2; 25322ac6984SEtienne Carriere uint32_t token_id = 0; 25422ac6984SEtienne Carriere const size_t out_size = sizeof(token_id) * TOKEN_COUNT; 25522ac6984SEtienne Carriere uint8_t *id = NULL; 25622ac6984SEtienne Carriere 25722ac6984SEtienne Carriere if (ptypes != exp_pt || 25822ac6984SEtienne Carriere params[0].memref.size != TEE_PARAM0_SIZE_MIN) 25922ac6984SEtienne Carriere return PKCS11_CKR_ARGUMENTS_BAD; 26022ac6984SEtienne Carriere 26122ac6984SEtienne Carriere if (out->memref.size < out_size) { 26222ac6984SEtienne Carriere out->memref.size = out_size; 26322ac6984SEtienne Carriere 26422ac6984SEtienne Carriere if (out->memref.buffer) 26522ac6984SEtienne Carriere return PKCS11_CKR_BUFFER_TOO_SMALL; 26622ac6984SEtienne Carriere else 26722ac6984SEtienne Carriere return PKCS11_CKR_OK; 26822ac6984SEtienne Carriere } 26922ac6984SEtienne Carriere 27022ac6984SEtienne Carriere for (token_id = 0, id = out->memref.buffer; token_id < TOKEN_COUNT; 27122ac6984SEtienne Carriere token_id++, id += sizeof(token_id)) 27222ac6984SEtienne Carriere TEE_MemMove(id, &token_id, sizeof(token_id)); 27322ac6984SEtienne Carriere 27422ac6984SEtienne Carriere out->memref.size = out_size; 27522ac6984SEtienne Carriere 27622ac6984SEtienne Carriere return PKCS11_CKR_OK; 27722ac6984SEtienne Carriere } 278ce94efefSEtienne Carriere 279b3ac5035SEtienne Carriere static void pad_str(uint8_t *str, size_t size) 280b3ac5035SEtienne Carriere { 281b3ac5035SEtienne Carriere int n = strnlen((char *)str, size); 282b3ac5035SEtienne Carriere 283b3ac5035SEtienne Carriere TEE_MemFill(str + n, ' ', size - n); 284b3ac5035SEtienne Carriere } 285b3ac5035SEtienne Carriere 286d628ebd9SEtienne Carriere static void set_token_description(struct pkcs11_slot_info *info) 287d628ebd9SEtienne Carriere { 288d628ebd9SEtienne Carriere char desc[sizeof(info->slot_description) + 1] = { 0 }; 289d628ebd9SEtienne Carriere TEE_UUID dev_id = { }; 290d628ebd9SEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 291d628ebd9SEtienne Carriere int n = 0; 292d628ebd9SEtienne Carriere 293d628ebd9SEtienne Carriere res = TEE_GetPropertyAsUUID(TEE_PROPSET_TEE_IMPLEMENTATION, 294d628ebd9SEtienne Carriere "gpd.tee.deviceID", &dev_id); 295d628ebd9SEtienne Carriere if (res == TEE_SUCCESS) { 296d628ebd9SEtienne Carriere n = snprintk(desc, sizeof(desc), PKCS11_SLOT_DESCRIPTION 297d628ebd9SEtienne Carriere " - TEE UUID %pUl", (void *)&dev_id); 298d628ebd9SEtienne Carriere } else { 299d628ebd9SEtienne Carriere n = snprintf(desc, sizeof(desc), PKCS11_SLOT_DESCRIPTION 300d628ebd9SEtienne Carriere " - No TEE UUID"); 301d628ebd9SEtienne Carriere } 302d628ebd9SEtienne Carriere if (n < 0 || n >= (int)sizeof(desc)) 303d628ebd9SEtienne Carriere TEE_Panic(0); 304d628ebd9SEtienne Carriere 305d628ebd9SEtienne Carriere TEE_MemMove(info->slot_description, desc, n); 306d628ebd9SEtienne Carriere pad_str(info->slot_description, sizeof(info->slot_description)); 307d628ebd9SEtienne Carriere } 308d628ebd9SEtienne Carriere 3094daf39b3SJens Wiklander enum pkcs11_rc entry_ck_slot_info(uint32_t ptypes, TEE_Param *params) 310ce94efefSEtienne Carriere { 311ce94efefSEtienne Carriere const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 312ce94efefSEtienne Carriere TEE_PARAM_TYPE_NONE, 313ce94efefSEtienne Carriere TEE_PARAM_TYPE_MEMREF_OUTPUT, 314ce94efefSEtienne Carriere TEE_PARAM_TYPE_NONE); 31539b43b78SJens Wiklander TEE_Param *ctrl = params; 31639b43b78SJens Wiklander TEE_Param *out = params + 2; 3174daf39b3SJens Wiklander enum pkcs11_rc rc = PKCS11_CKR_OK; 318ce94efefSEtienne Carriere struct serialargs ctrlargs = { }; 319ce94efefSEtienne Carriere uint32_t token_id = 0; 320ce94efefSEtienne Carriere struct pkcs11_slot_info info = { 321ce94efefSEtienne Carriere .slot_description = PKCS11_SLOT_DESCRIPTION, 322ce94efefSEtienne Carriere .manufacturer_id = PKCS11_SLOT_MANUFACTURER, 323ce94efefSEtienne Carriere .flags = PKCS11_CKFS_TOKEN_PRESENT, 324ce94efefSEtienne Carriere .hardware_version = PKCS11_SLOT_HW_VERSION, 325ce94efefSEtienne Carriere .firmware_version = PKCS11_SLOT_FW_VERSION, 326ce94efefSEtienne Carriere }; 327ce94efefSEtienne Carriere 328ce94efefSEtienne Carriere COMPILE_TIME_ASSERT(sizeof(PKCS11_SLOT_DESCRIPTION) <= 329ce94efefSEtienne Carriere sizeof(info.slot_description)); 330ce94efefSEtienne Carriere COMPILE_TIME_ASSERT(sizeof(PKCS11_SLOT_MANUFACTURER) <= 331ce94efefSEtienne Carriere sizeof(info.manufacturer_id)); 332ce94efefSEtienne Carriere 333ce94efefSEtienne Carriere if (ptypes != exp_pt || out->memref.size != sizeof(info)) 334ce94efefSEtienne Carriere return PKCS11_CKR_ARGUMENTS_BAD; 335ce94efefSEtienne Carriere 336ce94efefSEtienne Carriere serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 337ce94efefSEtienne Carriere 3384daf39b3SJens Wiklander rc = serialargs_get(&ctrlargs, &token_id, sizeof(token_id)); 3394daf39b3SJens Wiklander if (rc) 3404daf39b3SJens Wiklander return rc; 341ce94efefSEtienne Carriere 342ce94efefSEtienne Carriere if (serialargs_remaining_bytes(&ctrlargs)) 343ce94efefSEtienne Carriere return PKCS11_CKR_ARGUMENTS_BAD; 344ce94efefSEtienne Carriere 34529b0949aSEtienne Carriere if (!get_token(token_id)) 346ce94efefSEtienne Carriere return PKCS11_CKR_SLOT_ID_INVALID; 347ce94efefSEtienne Carriere 348d628ebd9SEtienne Carriere set_token_description(&info); 349d628ebd9SEtienne Carriere 350b3ac5035SEtienne Carriere pad_str(info.manufacturer_id, sizeof(info.manufacturer_id)); 351ce94efefSEtienne Carriere 352ce94efefSEtienne Carriere out->memref.size = sizeof(info); 353ce94efefSEtienne Carriere TEE_MemMove(out->memref.buffer, &info, out->memref.size); 354ce94efefSEtienne Carriere 355ce94efefSEtienne Carriere return PKCS11_CKR_OK; 356ce94efefSEtienne Carriere } 357030e7392SEtienne Carriere 3584daf39b3SJens Wiklander enum pkcs11_rc entry_ck_token_info(uint32_t ptypes, TEE_Param *params) 359030e7392SEtienne Carriere { 360030e7392SEtienne Carriere const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 361030e7392SEtienne Carriere TEE_PARAM_TYPE_NONE, 362030e7392SEtienne Carriere TEE_PARAM_TYPE_MEMREF_OUTPUT, 363030e7392SEtienne Carriere TEE_PARAM_TYPE_NONE); 36439b43b78SJens Wiklander TEE_Param *ctrl = params; 36539b43b78SJens Wiklander TEE_Param *out = params + 2; 3664daf39b3SJens Wiklander enum pkcs11_rc rc = PKCS11_CKR_OK; 367030e7392SEtienne Carriere struct serialargs ctrlargs = { }; 368030e7392SEtienne Carriere uint32_t token_id = 0; 369030e7392SEtienne Carriere struct ck_token *token = NULL; 370030e7392SEtienne Carriere struct pkcs11_token_info info = { 371030e7392SEtienne Carriere .manufacturer_id = PKCS11_TOKEN_MANUFACTURER, 372030e7392SEtienne Carriere .model = PKCS11_TOKEN_MODEL, 373030e7392SEtienne Carriere .max_session_count = UINT32_MAX, 374030e7392SEtienne Carriere .max_rw_session_count = UINT32_MAX, 375030e7392SEtienne Carriere .max_pin_len = PKCS11_TOKEN_PIN_SIZE_MAX, 376030e7392SEtienne Carriere .min_pin_len = PKCS11_TOKEN_PIN_SIZE_MIN, 377030e7392SEtienne Carriere .total_public_memory = UINT32_MAX, 378030e7392SEtienne Carriere .free_public_memory = UINT32_MAX, 379030e7392SEtienne Carriere .total_private_memory = UINT32_MAX, 380030e7392SEtienne Carriere .free_private_memory = UINT32_MAX, 381030e7392SEtienne Carriere .hardware_version = PKCS11_TOKEN_HW_VERSION, 382030e7392SEtienne Carriere .firmware_version = PKCS11_TOKEN_FW_VERSION, 383030e7392SEtienne Carriere }; 38402b4d42aSEtienne Carriere char sn[sizeof(info.serial_number) + 1] = { 0 }; 38502b4d42aSEtienne Carriere int n = 0; 386030e7392SEtienne Carriere 387030e7392SEtienne Carriere if (ptypes != exp_pt || out->memref.size != sizeof(info)) 388030e7392SEtienne Carriere return PKCS11_CKR_ARGUMENTS_BAD; 389030e7392SEtienne Carriere 390030e7392SEtienne Carriere serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 391030e7392SEtienne Carriere 3924daf39b3SJens Wiklander rc = serialargs_get(&ctrlargs, &token_id, sizeof(token_id)); 3934daf39b3SJens Wiklander if (rc) 3944daf39b3SJens Wiklander return rc; 395030e7392SEtienne Carriere 396030e7392SEtienne Carriere if (serialargs_remaining_bytes(&ctrlargs)) 397030e7392SEtienne Carriere return PKCS11_CKR_ARGUMENTS_BAD; 398030e7392SEtienne Carriere 399030e7392SEtienne Carriere token = get_token(token_id); 400030e7392SEtienne Carriere if (!token) 401030e7392SEtienne Carriere return PKCS11_CKR_SLOT_ID_INVALID; 402030e7392SEtienne Carriere 403030e7392SEtienne Carriere pad_str(info.manufacturer_id, sizeof(info.manufacturer_id)); 404030e7392SEtienne Carriere pad_str(info.model, sizeof(info.model)); 40502b4d42aSEtienne Carriere 40602b4d42aSEtienne Carriere n = snprintf(sn, sizeof(sn), "%0*"PRIu32, 40702b4d42aSEtienne Carriere (int)sizeof(info.serial_number), token_id); 40802b4d42aSEtienne Carriere if (n != (int)sizeof(info.serial_number)) 40902b4d42aSEtienne Carriere TEE_Panic(0); 41002b4d42aSEtienne Carriere 41102b4d42aSEtienne Carriere TEE_MemMove(info.serial_number, sn, sizeof(info.serial_number)); 412030e7392SEtienne Carriere pad_str(info.serial_number, sizeof(info.serial_number)); 413030e7392SEtienne Carriere 414030e7392SEtienne Carriere TEE_MemMove(info.label, token->db_main->label, sizeof(info.label)); 415030e7392SEtienne Carriere 416030e7392SEtienne Carriere info.flags = token->db_main->flags; 417030e7392SEtienne Carriere info.session_count = token->session_count; 418030e7392SEtienne Carriere info.rw_session_count = token->rw_session_count; 419030e7392SEtienne Carriere 420030e7392SEtienne Carriere TEE_MemMove(out->memref.buffer, &info, sizeof(info)); 421030e7392SEtienne Carriere 422030e7392SEtienne Carriere return PKCS11_CKR_OK; 423030e7392SEtienne Carriere } 4246f74919dSEtienne Carriere 4256f74919dSEtienne Carriere static void dmsg_print_supported_mechanism(unsigned int token_id __maybe_unused, 4266f74919dSEtienne Carriere uint32_t *array __maybe_unused, 4276f74919dSEtienne Carriere size_t count __maybe_unused) 4286f74919dSEtienne Carriere { 4296f74919dSEtienne Carriere size_t __maybe_unused n = 0; 4306f74919dSEtienne Carriere 4316f74919dSEtienne Carriere if (TRACE_LEVEL < TRACE_DEBUG) 4326f74919dSEtienne Carriere return; 4336f74919dSEtienne Carriere 4346f74919dSEtienne Carriere for (n = 0; n < count; n++) 4356f74919dSEtienne Carriere DMSG("PKCS11 token %"PRIu32": mechanism 0x%04"PRIx32": %s", 4366f74919dSEtienne Carriere token_id, array[n], id2str_mechanism(array[n])); 4376f74919dSEtienne Carriere } 4386f74919dSEtienne Carriere 4394daf39b3SJens Wiklander enum pkcs11_rc entry_ck_token_mecha_ids(uint32_t ptypes, TEE_Param *params) 4406f74919dSEtienne Carriere { 4416f74919dSEtienne Carriere const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 4426f74919dSEtienne Carriere TEE_PARAM_TYPE_NONE, 4436f74919dSEtienne Carriere TEE_PARAM_TYPE_MEMREF_OUTPUT, 4446f74919dSEtienne Carriere TEE_PARAM_TYPE_NONE); 44539b43b78SJens Wiklander TEE_Param *ctrl = params; 44639b43b78SJens Wiklander TEE_Param *out = params + 2; 4474daf39b3SJens Wiklander enum pkcs11_rc rc = PKCS11_CKR_OK; 4486f74919dSEtienne Carriere struct serialargs ctrlargs = { }; 4496f74919dSEtienne Carriere uint32_t token_id = 0; 4506f74919dSEtienne Carriere struct ck_token __maybe_unused *token = NULL; 4516f74919dSEtienne Carriere size_t count = 0; 4526f74919dSEtienne Carriere uint32_t *array = NULL; 4536f74919dSEtienne Carriere 4546f74919dSEtienne Carriere if (ptypes != exp_pt) 4556f74919dSEtienne Carriere return PKCS11_CKR_ARGUMENTS_BAD; 4566f74919dSEtienne Carriere 4576f74919dSEtienne Carriere serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 4586f74919dSEtienne Carriere 4594daf39b3SJens Wiklander rc = serialargs_get(&ctrlargs, &token_id, sizeof(token_id)); 4604daf39b3SJens Wiklander if (rc) 4614daf39b3SJens Wiklander return rc; 4626f74919dSEtienne Carriere 4636f74919dSEtienne Carriere if (serialargs_remaining_bytes(&ctrlargs)) 4646f74919dSEtienne Carriere return PKCS11_CKR_ARGUMENTS_BAD; 4656f74919dSEtienne Carriere 4666f74919dSEtienne Carriere token = get_token(token_id); 4676f74919dSEtienne Carriere if (!token) 4686f74919dSEtienne Carriere return PKCS11_CKR_SLOT_ID_INVALID; 4696f74919dSEtienne Carriere 4706f74919dSEtienne Carriere count = out->memref.size / sizeof(*array); 4716f74919dSEtienne Carriere array = tee_malloc_mechanism_list(&count); 4726f74919dSEtienne Carriere 4736f74919dSEtienne Carriere if (out->memref.size < count * sizeof(*array)) { 4746f74919dSEtienne Carriere assert(!array); 4756f74919dSEtienne Carriere out->memref.size = count * sizeof(*array); 4766459f267SEtienne Carriere if (out->memref.buffer) 4776f74919dSEtienne Carriere return PKCS11_CKR_BUFFER_TOO_SMALL; 4786459f267SEtienne Carriere else 4796459f267SEtienne Carriere return PKCS11_CKR_OK; 4806f74919dSEtienne Carriere } 4816f74919dSEtienne Carriere 4826f74919dSEtienne Carriere if (!array) 4836f74919dSEtienne Carriere return PKCS11_CKR_DEVICE_MEMORY; 4846f74919dSEtienne Carriere 4856f74919dSEtienne Carriere dmsg_print_supported_mechanism(token_id, array, count); 4866f74919dSEtienne Carriere 4876f74919dSEtienne Carriere out->memref.size = count * sizeof(*array); 4886f74919dSEtienne Carriere TEE_MemMove(out->memref.buffer, array, out->memref.size); 4896f74919dSEtienne Carriere 4906f74919dSEtienne Carriere TEE_Free(array); 4916f74919dSEtienne Carriere 4924daf39b3SJens Wiklander return rc; 4936f74919dSEtienne Carriere } 4941d3ebedbSEtienne Carriere 4954daf39b3SJens Wiklander enum pkcs11_rc entry_ck_token_mecha_info(uint32_t ptypes, TEE_Param *params) 4961d3ebedbSEtienne Carriere { 4971d3ebedbSEtienne Carriere const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 4981d3ebedbSEtienne Carriere TEE_PARAM_TYPE_NONE, 4991d3ebedbSEtienne Carriere TEE_PARAM_TYPE_MEMREF_OUTPUT, 5001d3ebedbSEtienne Carriere TEE_PARAM_TYPE_NONE); 50139b43b78SJens Wiklander TEE_Param *ctrl = params; 50239b43b78SJens Wiklander TEE_Param *out = params + 2; 5034daf39b3SJens Wiklander enum pkcs11_rc rc = PKCS11_CKR_OK; 5041d3ebedbSEtienne Carriere struct serialargs ctrlargs = { }; 5051d3ebedbSEtienne Carriere uint32_t token_id = 0; 5061d3ebedbSEtienne Carriere uint32_t type = 0; 5071d3ebedbSEtienne Carriere struct ck_token *token = NULL; 5081d3ebedbSEtienne Carriere struct pkcs11_mechanism_info info = { }; 5091d3ebedbSEtienne Carriere 5101d3ebedbSEtienne Carriere if (ptypes != exp_pt || out->memref.size != sizeof(info)) 5111d3ebedbSEtienne Carriere return PKCS11_CKR_ARGUMENTS_BAD; 5121d3ebedbSEtienne Carriere 5131d3ebedbSEtienne Carriere serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 5141d3ebedbSEtienne Carriere 5154daf39b3SJens Wiklander rc = serialargs_get(&ctrlargs, &token_id, sizeof(uint32_t)); 5164daf39b3SJens Wiklander if (rc) 5174daf39b3SJens Wiklander return rc; 5181d3ebedbSEtienne Carriere 5194daf39b3SJens Wiklander rc = serialargs_get(&ctrlargs, &type, sizeof(uint32_t)); 5204daf39b3SJens Wiklander if (rc) 5214daf39b3SJens Wiklander return rc; 5221d3ebedbSEtienne Carriere 5231d3ebedbSEtienne Carriere if (serialargs_remaining_bytes(&ctrlargs)) 5241d3ebedbSEtienne Carriere return PKCS11_CKR_ARGUMENTS_BAD; 5251d3ebedbSEtienne Carriere 5261d3ebedbSEtienne Carriere token = get_token(token_id); 5271d3ebedbSEtienne Carriere if (!token) 5281d3ebedbSEtienne Carriere return PKCS11_CKR_SLOT_ID_INVALID; 5291d3ebedbSEtienne Carriere 5301d3ebedbSEtienne Carriere if (!mechanism_is_valid(type)) 5311d3ebedbSEtienne Carriere return PKCS11_CKR_MECHANISM_INVALID; 5321d3ebedbSEtienne Carriere 5331d3ebedbSEtienne Carriere info.flags = mechanism_supported_flags(type); 5341d3ebedbSEtienne Carriere 5352d0cd829SRuchika Gupta pkcs11_mechanism_supported_key_sizes(type, &info.min_key_size, 5361d3ebedbSEtienne Carriere &info.max_key_size); 5371d3ebedbSEtienne Carriere 5381d3ebedbSEtienne Carriere TEE_MemMove(out->memref.buffer, &info, sizeof(info)); 5391d3ebedbSEtienne Carriere 5401d3ebedbSEtienne Carriere DMSG("PKCS11 token %"PRIu32": mechanism 0x%"PRIx32" info", 5411d3ebedbSEtienne Carriere token_id, type); 5421d3ebedbSEtienne Carriere 5431d3ebedbSEtienne Carriere return PKCS11_CKR_OK; 5441d3ebedbSEtienne Carriere } 5456e4f8f17SEtienne Carriere 5466e4f8f17SEtienne Carriere /* Select the ReadOnly or ReadWrite state for session login state */ 5476e4f8f17SEtienne Carriere static void set_session_state(struct pkcs11_client *client, 5486e4f8f17SEtienne Carriere struct pkcs11_session *session, bool readonly) 5496e4f8f17SEtienne Carriere { 5506e4f8f17SEtienne Carriere struct pkcs11_session *sess = NULL; 5516e4f8f17SEtienne Carriere enum pkcs11_session_state state = PKCS11_CKS_RO_PUBLIC_SESSION; 5526e4f8f17SEtienne Carriere 5536e4f8f17SEtienne Carriere /* Default to public session if no session already registered */ 5546e4f8f17SEtienne Carriere if (readonly) 5556e4f8f17SEtienne Carriere state = PKCS11_CKS_RO_PUBLIC_SESSION; 5566e4f8f17SEtienne Carriere else 5576e4f8f17SEtienne Carriere state = PKCS11_CKS_RW_PUBLIC_SESSION; 5586e4f8f17SEtienne Carriere 5596e4f8f17SEtienne Carriere /* 5606e4f8f17SEtienne Carriere * No need to check all client sessions, the first found in 5616e4f8f17SEtienne Carriere * target token gives client login configuration. 5626e4f8f17SEtienne Carriere */ 5636e4f8f17SEtienne Carriere TAILQ_FOREACH(sess, &client->session_list, link) { 5646e4f8f17SEtienne Carriere assert(sess != session); 5656e4f8f17SEtienne Carriere 5666e4f8f17SEtienne Carriere if (sess->token == session->token) { 5676e4f8f17SEtienne Carriere switch (sess->state) { 5686e4f8f17SEtienne Carriere case PKCS11_CKS_RW_PUBLIC_SESSION: 5696e4f8f17SEtienne Carriere case PKCS11_CKS_RO_PUBLIC_SESSION: 5706e4f8f17SEtienne Carriere if (readonly) 5716e4f8f17SEtienne Carriere state = PKCS11_CKS_RO_PUBLIC_SESSION; 5726e4f8f17SEtienne Carriere else 5736e4f8f17SEtienne Carriere state = PKCS11_CKS_RW_PUBLIC_SESSION; 5746e4f8f17SEtienne Carriere break; 5756e4f8f17SEtienne Carriere case PKCS11_CKS_RO_USER_FUNCTIONS: 5766e4f8f17SEtienne Carriere case PKCS11_CKS_RW_USER_FUNCTIONS: 5776e4f8f17SEtienne Carriere if (readonly) 5786e4f8f17SEtienne Carriere state = PKCS11_CKS_RO_USER_FUNCTIONS; 5796e4f8f17SEtienne Carriere else 5806e4f8f17SEtienne Carriere state = PKCS11_CKS_RW_USER_FUNCTIONS; 5816e4f8f17SEtienne Carriere break; 5826e4f8f17SEtienne Carriere case PKCS11_CKS_RW_SO_FUNCTIONS: 5836e4f8f17SEtienne Carriere if (readonly) 5846e4f8f17SEtienne Carriere TEE_Panic(0); 5856e4f8f17SEtienne Carriere else 5866e4f8f17SEtienne Carriere state = PKCS11_CKS_RW_SO_FUNCTIONS; 5876e4f8f17SEtienne Carriere break; 5886e4f8f17SEtienne Carriere default: 5896e4f8f17SEtienne Carriere TEE_Panic(0); 5906e4f8f17SEtienne Carriere } 5916e4f8f17SEtienne Carriere break; 5926e4f8f17SEtienne Carriere } 5936e4f8f17SEtienne Carriere } 5946e4f8f17SEtienne Carriere 5956e4f8f17SEtienne Carriere session->state = state; 5966e4f8f17SEtienne Carriere } 5976e4f8f17SEtienne Carriere 5984daf39b3SJens Wiklander enum pkcs11_rc entry_ck_open_session(struct pkcs11_client *client, 5996e4f8f17SEtienne Carriere uint32_t ptypes, TEE_Param *params) 6006e4f8f17SEtienne Carriere { 6016e4f8f17SEtienne Carriere const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 6026e4f8f17SEtienne Carriere TEE_PARAM_TYPE_NONE, 6036e4f8f17SEtienne Carriere TEE_PARAM_TYPE_MEMREF_OUTPUT, 6046e4f8f17SEtienne Carriere TEE_PARAM_TYPE_NONE); 60539b43b78SJens Wiklander TEE_Param *ctrl = params; 60639b43b78SJens Wiklander TEE_Param *out = params + 2; 6074daf39b3SJens Wiklander enum pkcs11_rc rc = PKCS11_CKR_OK; 6086e4f8f17SEtienne Carriere struct serialargs ctrlargs = { }; 6096e4f8f17SEtienne Carriere uint32_t token_id = 0; 6106e4f8f17SEtienne Carriere uint32_t flags = 0; 6116e4f8f17SEtienne Carriere struct ck_token *token = NULL; 6126e4f8f17SEtienne Carriere struct pkcs11_session *session = NULL; 6136e4f8f17SEtienne Carriere bool readonly = false; 6146e4f8f17SEtienne Carriere 6156e4f8f17SEtienne Carriere if (!client || ptypes != exp_pt || 6166e4f8f17SEtienne Carriere out->memref.size != sizeof(session->handle)) 6176e4f8f17SEtienne Carriere return PKCS11_CKR_ARGUMENTS_BAD; 6186e4f8f17SEtienne Carriere 6196e4f8f17SEtienne Carriere serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 6206e4f8f17SEtienne Carriere 6214daf39b3SJens Wiklander rc = serialargs_get(&ctrlargs, &token_id, sizeof(token_id)); 6224daf39b3SJens Wiklander if (rc) 6234daf39b3SJens Wiklander return rc; 6246e4f8f17SEtienne Carriere 6254daf39b3SJens Wiklander rc = serialargs_get(&ctrlargs, &flags, sizeof(flags)); 6264daf39b3SJens Wiklander if (rc) 6274daf39b3SJens Wiklander return rc; 6286e4f8f17SEtienne Carriere 6296e4f8f17SEtienne Carriere if (serialargs_remaining_bytes(&ctrlargs)) 6306e4f8f17SEtienne Carriere return PKCS11_CKR_ARGUMENTS_BAD; 6316e4f8f17SEtienne Carriere 6326e4f8f17SEtienne Carriere token = get_token(token_id); 6336e4f8f17SEtienne Carriere if (!token) 6346e4f8f17SEtienne Carriere return PKCS11_CKR_SLOT_ID_INVALID; 6356e4f8f17SEtienne Carriere 6366e4f8f17SEtienne Carriere /* Sanitize session flags */ 63708774c86SVesa Jääskeläinen if (!(flags & PKCS11_CKFSS_SERIAL_SESSION)) 63808774c86SVesa Jääskeläinen return PKCS11_CKR_SESSION_PARALLEL_NOT_SUPPORTED; 63908774c86SVesa Jääskeläinen 64008774c86SVesa Jääskeläinen if (flags & ~(PKCS11_CKFSS_RW_SESSION | PKCS11_CKFSS_SERIAL_SESSION)) 6416e4f8f17SEtienne Carriere return PKCS11_CKR_ARGUMENTS_BAD; 6426e4f8f17SEtienne Carriere 6436e4f8f17SEtienne Carriere readonly = !(flags & PKCS11_CKFSS_RW_SESSION); 6446e4f8f17SEtienne Carriere 6456e4f8f17SEtienne Carriere if (!readonly && token->state == PKCS11_TOKEN_READ_ONLY) 6466e4f8f17SEtienne Carriere return PKCS11_CKR_TOKEN_WRITE_PROTECTED; 6476e4f8f17SEtienne Carriere 6486e4f8f17SEtienne Carriere if (readonly) { 6496e4f8f17SEtienne Carriere /* Specifically reject read-only session under SO login */ 6506e4f8f17SEtienne Carriere TAILQ_FOREACH(session, &client->session_list, link) 6516e4f8f17SEtienne Carriere if (pkcs11_session_is_so(session)) 6526e4f8f17SEtienne Carriere return PKCS11_CKR_SESSION_READ_WRITE_SO_EXISTS; 6536e4f8f17SEtienne Carriere } 6546e4f8f17SEtienne Carriere 6556e4f8f17SEtienne Carriere session = TEE_Malloc(sizeof(*session), TEE_MALLOC_FILL_ZERO); 6566e4f8f17SEtienne Carriere if (!session) 6576e4f8f17SEtienne Carriere return PKCS11_CKR_DEVICE_MEMORY; 6586e4f8f17SEtienne Carriere 6596e4f8f17SEtienne Carriere session->handle = handle_get(&client->session_handle_db, session); 6606e4f8f17SEtienne Carriere if (!session->handle) { 6616e4f8f17SEtienne Carriere TEE_Free(session); 6626e4f8f17SEtienne Carriere return PKCS11_CKR_DEVICE_MEMORY; 6636e4f8f17SEtienne Carriere } 6646e4f8f17SEtienne Carriere 6656e4f8f17SEtienne Carriere session->token = token; 6666e4f8f17SEtienne Carriere session->client = client; 6676e4f8f17SEtienne Carriere 668b56b3d07SJens Wiklander LIST_INIT(&session->object_list); 669b56b3d07SJens Wiklander 6706e4f8f17SEtienne Carriere set_session_state(client, session, readonly); 6716e4f8f17SEtienne Carriere 6726e4f8f17SEtienne Carriere TAILQ_INSERT_HEAD(&client->session_list, session, link); 6736e4f8f17SEtienne Carriere 6746e4f8f17SEtienne Carriere session->token->session_count++; 6756e4f8f17SEtienne Carriere if (!readonly) 6766e4f8f17SEtienne Carriere session->token->rw_session_count++; 6776e4f8f17SEtienne Carriere 6786e4f8f17SEtienne Carriere TEE_MemMove(out->memref.buffer, &session->handle, 6796e4f8f17SEtienne Carriere sizeof(session->handle)); 6806e4f8f17SEtienne Carriere 6816e4f8f17SEtienne Carriere DMSG("Open PKCS11 session %"PRIu32, session->handle); 6826e4f8f17SEtienne Carriere 6836e4f8f17SEtienne Carriere return PKCS11_CKR_OK; 6846e4f8f17SEtienne Carriere } 6856e4f8f17SEtienne Carriere 6866e4f8f17SEtienne Carriere static void close_ck_session(struct pkcs11_session *session) 6876e4f8f17SEtienne Carriere { 68855e6965cSEtienne Carriere release_active_processing(session); 689bc555ee0SVesa Jääskeläinen release_session_find_obj_context(session); 69055e6965cSEtienne Carriere 691bc555ee0SVesa Jääskeläinen /* Release all session objects */ 692b56b3d07SJens Wiklander while (!LIST_EMPTY(&session->object_list)) 693b56b3d07SJens Wiklander destroy_object(session, 694b56b3d07SJens Wiklander LIST_FIRST(&session->object_list), true); 695b56b3d07SJens Wiklander 6966e4f8f17SEtienne Carriere TAILQ_REMOVE(&session->client->session_list, session, link); 6976e4f8f17SEtienne Carriere handle_put(&session->client->session_handle_db, session->handle); 6986e4f8f17SEtienne Carriere 6996e4f8f17SEtienne Carriere session->token->session_count--; 7006e4f8f17SEtienne Carriere if (pkcs11_session_is_read_write(session)) 7016e4f8f17SEtienne Carriere session->token->rw_session_count--; 7026e4f8f17SEtienne Carriere 7036e4f8f17SEtienne Carriere DMSG("Close PKCS11 session %"PRIu32, session->handle); 7049325ea3dSJerome Forissier 7059325ea3dSJerome Forissier TEE_Free(session); 7066e4f8f17SEtienne Carriere } 7076e4f8f17SEtienne Carriere 7084daf39b3SJens Wiklander enum pkcs11_rc entry_ck_close_session(struct pkcs11_client *client, 7096e4f8f17SEtienne Carriere uint32_t ptypes, TEE_Param *params) 7106e4f8f17SEtienne Carriere { 7116e4f8f17SEtienne Carriere const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 7126e4f8f17SEtienne Carriere TEE_PARAM_TYPE_NONE, 7136e4f8f17SEtienne Carriere TEE_PARAM_TYPE_NONE, 7146e4f8f17SEtienne Carriere TEE_PARAM_TYPE_NONE); 71539b43b78SJens Wiklander TEE_Param *ctrl = params; 7164daf39b3SJens Wiklander enum pkcs11_rc rc = PKCS11_CKR_OK; 7176e4f8f17SEtienne Carriere struct serialargs ctrlargs = { }; 7186e4f8f17SEtienne Carriere struct pkcs11_session *session = NULL; 7196e4f8f17SEtienne Carriere 7206e4f8f17SEtienne Carriere if (!client || ptypes != exp_pt) 7216e4f8f17SEtienne Carriere return PKCS11_CKR_ARGUMENTS_BAD; 7226e4f8f17SEtienne Carriere 7236e4f8f17SEtienne Carriere serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 7246e4f8f17SEtienne Carriere 7254daf39b3SJens Wiklander rc = serialargs_get_session_from_handle(&ctrlargs, client, &session); 7264daf39b3SJens Wiklander if (rc) 7274daf39b3SJens Wiklander return rc; 7286e4f8f17SEtienne Carriere 7296e4f8f17SEtienne Carriere if (serialargs_remaining_bytes(&ctrlargs)) 7306e4f8f17SEtienne Carriere return PKCS11_CKR_ARGUMENTS_BAD; 7316e4f8f17SEtienne Carriere 7326e4f8f17SEtienne Carriere close_ck_session(session); 7336e4f8f17SEtienne Carriere 7346e4f8f17SEtienne Carriere return PKCS11_CKR_OK; 7356e4f8f17SEtienne Carriere } 7366e4f8f17SEtienne Carriere 7374daf39b3SJens Wiklander enum pkcs11_rc entry_ck_close_all_sessions(struct pkcs11_client *client, 7386e4f8f17SEtienne Carriere uint32_t ptypes, TEE_Param *params) 7396e4f8f17SEtienne Carriere { 7406e4f8f17SEtienne Carriere const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 7416e4f8f17SEtienne Carriere TEE_PARAM_TYPE_NONE, 7426e4f8f17SEtienne Carriere TEE_PARAM_TYPE_NONE, 7436e4f8f17SEtienne Carriere TEE_PARAM_TYPE_NONE); 74439b43b78SJens Wiklander TEE_Param *ctrl = params; 7454daf39b3SJens Wiklander enum pkcs11_rc rc = PKCS11_CKR_OK; 7466e4f8f17SEtienne Carriere struct serialargs ctrlargs = { }; 7476e4f8f17SEtienne Carriere uint32_t token_id = 0; 7486e4f8f17SEtienne Carriere struct ck_token *token = NULL; 7496e4f8f17SEtienne Carriere struct pkcs11_session *session = NULL; 7506e4f8f17SEtienne Carriere struct pkcs11_session *next = NULL; 7516e4f8f17SEtienne Carriere 7526e4f8f17SEtienne Carriere if (!client || ptypes != exp_pt) 7536e4f8f17SEtienne Carriere return PKCS11_CKR_ARGUMENTS_BAD; 7546e4f8f17SEtienne Carriere 7556e4f8f17SEtienne Carriere serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 7566e4f8f17SEtienne Carriere 7574daf39b3SJens Wiklander rc = serialargs_get(&ctrlargs, &token_id, sizeof(uint32_t)); 7584daf39b3SJens Wiklander if (rc) 7594daf39b3SJens Wiklander return rc; 7606e4f8f17SEtienne Carriere 7616e4f8f17SEtienne Carriere if (serialargs_remaining_bytes(&ctrlargs)) 7626e4f8f17SEtienne Carriere return PKCS11_CKR_ARGUMENTS_BAD; 7636e4f8f17SEtienne Carriere 7646e4f8f17SEtienne Carriere token = get_token(token_id); 7656e4f8f17SEtienne Carriere if (!token) 7666e4f8f17SEtienne Carriere return PKCS11_CKR_SLOT_ID_INVALID; 7676e4f8f17SEtienne Carriere 7686e4f8f17SEtienne Carriere DMSG("Close all sessions for PKCS11 token %"PRIu32, token_id); 7696e4f8f17SEtienne Carriere 7706e4f8f17SEtienne Carriere TAILQ_FOREACH_SAFE(session, &client->session_list, link, next) 7716e4f8f17SEtienne Carriere if (session->token == token) 7726e4f8f17SEtienne Carriere close_ck_session(session); 7736e4f8f17SEtienne Carriere 7746e4f8f17SEtienne Carriere return PKCS11_CKR_OK; 7756e4f8f17SEtienne Carriere } 7766e4f8f17SEtienne Carriere 7774daf39b3SJens Wiklander enum pkcs11_rc entry_ck_session_info(struct pkcs11_client *client, 7786e4f8f17SEtienne Carriere uint32_t ptypes, TEE_Param *params) 7796e4f8f17SEtienne Carriere { 7806e4f8f17SEtienne Carriere const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 7816e4f8f17SEtienne Carriere TEE_PARAM_TYPE_NONE, 7826e4f8f17SEtienne Carriere TEE_PARAM_TYPE_MEMREF_OUTPUT, 7836e4f8f17SEtienne Carriere TEE_PARAM_TYPE_NONE); 78439b43b78SJens Wiklander TEE_Param *ctrl = params; 78539b43b78SJens Wiklander TEE_Param *out = params + 2; 7864daf39b3SJens Wiklander enum pkcs11_rc rc = PKCS11_CKR_OK; 7876e4f8f17SEtienne Carriere struct serialargs ctrlargs = { }; 7886e4f8f17SEtienne Carriere struct pkcs11_session *session = NULL; 7896e4f8f17SEtienne Carriere struct pkcs11_session_info info = { 7906e4f8f17SEtienne Carriere .flags = PKCS11_CKFSS_SERIAL_SESSION, 7916e4f8f17SEtienne Carriere }; 7926e4f8f17SEtienne Carriere 7936e4f8f17SEtienne Carriere if (!client || ptypes != exp_pt || out->memref.size != sizeof(info)) 7946e4f8f17SEtienne Carriere return PKCS11_CKR_ARGUMENTS_BAD; 7956e4f8f17SEtienne Carriere 7966e4f8f17SEtienne Carriere serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 7976e4f8f17SEtienne Carriere 7984daf39b3SJens Wiklander rc = serialargs_get_session_from_handle(&ctrlargs, client, &session); 7994daf39b3SJens Wiklander if (rc) 8004daf39b3SJens Wiklander return rc; 8016e4f8f17SEtienne Carriere 8026e4f8f17SEtienne Carriere if (serialargs_remaining_bytes(&ctrlargs)) 8036e4f8f17SEtienne Carriere return PKCS11_CKR_ARGUMENTS_BAD; 8046e4f8f17SEtienne Carriere 8056e4f8f17SEtienne Carriere info.slot_id = get_token_id(session->token); 8066e4f8f17SEtienne Carriere info.state = session->state; 8076e4f8f17SEtienne Carriere if (pkcs11_session_is_read_write(session)) 8086e4f8f17SEtienne Carriere info.flags |= PKCS11_CKFSS_RW_SESSION; 8096e4f8f17SEtienne Carriere 8106e4f8f17SEtienne Carriere TEE_MemMove(out->memref.buffer, &info, sizeof(info)); 8116e4f8f17SEtienne Carriere 8126e4f8f17SEtienne Carriere DMSG("Get find on PKCS11 session %"PRIu32, session->handle); 8136e4f8f17SEtienne Carriere 8146e4f8f17SEtienne Carriere return PKCS11_CKR_OK; 8156e4f8f17SEtienne Carriere } 816f485be04SJens Wiklander 8174daf39b3SJens Wiklander enum pkcs11_rc entry_ck_token_initialize(uint32_t ptypes, TEE_Param *params) 818f485be04SJens Wiklander { 819f485be04SJens Wiklander const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 820f485be04SJens Wiklander TEE_PARAM_TYPE_NONE, 821f485be04SJens Wiklander TEE_PARAM_TYPE_NONE, 822f485be04SJens Wiklander TEE_PARAM_TYPE_NONE); 823f485be04SJens Wiklander char label[PKCS11_TOKEN_LABEL_SIZE] = { 0 }; 824f485be04SJens Wiklander struct pkcs11_client *client = NULL; 825f485be04SJens Wiklander struct pkcs11_session *sess = NULL; 826f485be04SJens Wiklander enum pkcs11_rc rc = PKCS11_CKR_OK; 827f485be04SJens Wiklander struct serialargs ctrlargs = { }; 828f485be04SJens Wiklander struct ck_token *token = NULL; 829f485be04SJens Wiklander TEE_Param *ctrl = params; 830f485be04SJens Wiklander uint32_t token_id = 0; 831f485be04SJens Wiklander uint32_t pin_size = 0; 832f485be04SJens Wiklander void *pin = NULL; 8337f12c782SRobin van der Gracht struct pkcs11_object *obj = NULL; 834f485be04SJens Wiklander 835f485be04SJens Wiklander if (ptypes != exp_pt) 836f485be04SJens Wiklander return PKCS11_CKR_ARGUMENTS_BAD; 837f485be04SJens Wiklander 838f485be04SJens Wiklander serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 839f485be04SJens Wiklander 840f485be04SJens Wiklander rc = serialargs_get(&ctrlargs, &token_id, sizeof(uint32_t)); 841f485be04SJens Wiklander if (rc) 842f485be04SJens Wiklander return rc; 843f485be04SJens Wiklander 844f485be04SJens Wiklander rc = serialargs_get(&ctrlargs, &pin_size, sizeof(uint32_t)); 845f485be04SJens Wiklander if (rc) 846f485be04SJens Wiklander return rc; 847f485be04SJens Wiklander 848f485be04SJens Wiklander rc = serialargs_get(&ctrlargs, &label, PKCS11_TOKEN_LABEL_SIZE); 849f485be04SJens Wiklander if (rc) 850f485be04SJens Wiklander return rc; 851f485be04SJens Wiklander 852f485be04SJens Wiklander rc = serialargs_get_ptr(&ctrlargs, &pin, pin_size); 853f485be04SJens Wiklander if (rc) 854f485be04SJens Wiklander return rc; 855f485be04SJens Wiklander 856f485be04SJens Wiklander if (serialargs_remaining_bytes(&ctrlargs)) 857f485be04SJens Wiklander return PKCS11_CKR_ARGUMENTS_BAD; 858f485be04SJens Wiklander 859f485be04SJens Wiklander token = get_token(token_id); 860f485be04SJens Wiklander if (!token) 861f485be04SJens Wiklander return PKCS11_CKR_SLOT_ID_INVALID; 862f485be04SJens Wiklander 863f485be04SJens Wiklander if (token->db_main->flags & PKCS11_CKFT_SO_PIN_LOCKED) { 864f485be04SJens Wiklander IMSG("Token %"PRIu32": SO PIN locked", token_id); 865f485be04SJens Wiklander return PKCS11_CKR_PIN_LOCKED; 866f485be04SJens Wiklander } 867f485be04SJens Wiklander 868f485be04SJens Wiklander /* Check there's no open session on this token */ 869f485be04SJens Wiklander TAILQ_FOREACH(client, &pkcs11_client_list, link) 870f485be04SJens Wiklander TAILQ_FOREACH(sess, &client->session_list, link) 871f485be04SJens Wiklander if (sess->token == token) 872f485be04SJens Wiklander return PKCS11_CKR_SESSION_EXISTS; 873f485be04SJens Wiklander 874f1105cc5SVesa Jääskeläinen /* Verify authentication if token is already initialized */ 875f1105cc5SVesa Jääskeläinen if (token->db_main->flags & PKCS11_CKFT_TOKEN_INITIALIZED) { 876f1105cc5SVesa Jääskeläinen unsigned int pin_count = 0; 877f1105cc5SVesa Jääskeläinen 878f1105cc5SVesa Jääskeläinen if (IS_ENABLED(CFG_PKCS11_TA_AUTH_TEE_IDENTITY) && 879f1105cc5SVesa Jääskeläinen (token->db_main->flags & 880f1105cc5SVesa Jääskeläinen PKCS11_CKFT_PROTECTED_AUTHENTICATION_PATH)) { 8811a27b197SVesa Jääskeläinen /* Check TEE Identity based authentication if enabled */ 882f44a7a58SEtienne Carriere rc = verify_identity_auth(token, PKCS11_CKU_SO); 8831a27b197SVesa Jääskeläinen if (rc) 8841a27b197SVesa Jääskeläinen return rc; 885f485be04SJens Wiklander 886f485be04SJens Wiklander goto inited; 887f485be04SJens Wiklander } 888f485be04SJens Wiklander 889f1105cc5SVesa Jääskeläinen /* Check PIN based authentication */ 890f485be04SJens Wiklander rc = verify_pin(PKCS11_CKU_SO, pin, pin_size, 891f485be04SJens Wiklander token->db_main->so_pin_salt, 892f485be04SJens Wiklander token->db_main->so_pin_hash); 893f1105cc5SVesa Jääskeläinen if (!rc) 894f1105cc5SVesa Jääskeläinen goto inited; 895f485be04SJens Wiklander 896f485be04SJens Wiklander if (rc != PKCS11_CKR_PIN_INCORRECT) 897f485be04SJens Wiklander return rc; 898f485be04SJens Wiklander 899f485be04SJens Wiklander token->db_main->flags |= PKCS11_CKFT_SO_PIN_COUNT_LOW; 900f485be04SJens Wiklander token->db_main->so_pin_count++; 901f485be04SJens Wiklander 902f485be04SJens Wiklander pin_count = token->db_main->so_pin_count; 903f485be04SJens Wiklander if (pin_count == PKCS11_TOKEN_SO_PIN_COUNT_MAX - 1) 904f485be04SJens Wiklander token->db_main->flags |= PKCS11_CKFT_SO_PIN_FINAL_TRY; 905f485be04SJens Wiklander if (pin_count == PKCS11_TOKEN_SO_PIN_COUNT_MAX) 906f485be04SJens Wiklander token->db_main->flags |= PKCS11_CKFT_SO_PIN_LOCKED; 907f485be04SJens Wiklander 908f485be04SJens Wiklander update_persistent_db(token); 909f485be04SJens Wiklander 910f485be04SJens Wiklander return PKCS11_CKR_PIN_INCORRECT; 911f485be04SJens Wiklander } 912f485be04SJens Wiklander 913f1105cc5SVesa Jääskeläinen /* Initialize SO's authentication */ 914f1105cc5SVesa Jääskeläinen if (IS_ENABLED(CFG_PKCS11_TA_AUTH_TEE_IDENTITY) && !pin) { 915f1105cc5SVesa Jääskeläinen rc = setup_so_identity_auth_from_client(token); 916f1105cc5SVesa Jääskeläinen if (rc) 917f1105cc5SVesa Jääskeläinen return rc; 918f1105cc5SVesa Jääskeläinen } else { 919f1105cc5SVesa Jääskeläinen /* 920f1105cc5SVesa Jääskeläinen * The spec doesn't permit returning 921f1105cc5SVesa Jääskeläinen * PKCS11_CKR_PIN_LEN_RANGE for this function, take another 922f1105cc5SVesa Jääskeläinen * error code. 923f1105cc5SVesa Jääskeläinen */ 924f1105cc5SVesa Jääskeläinen if (pin_size < PKCS11_TOKEN_PIN_SIZE_MIN || 925f1105cc5SVesa Jääskeläinen pin_size > PKCS11_TOKEN_PIN_SIZE_MAX) 926f1105cc5SVesa Jääskeläinen return PKCS11_CKR_ARGUMENTS_BAD; 927f1105cc5SVesa Jääskeläinen 928f1105cc5SVesa Jääskeläinen rc = hash_pin(PKCS11_CKU_SO, pin, pin_size, 929f1105cc5SVesa Jääskeläinen &token->db_main->so_pin_salt, 930f1105cc5SVesa Jääskeläinen token->db_main->so_pin_hash); 931f1105cc5SVesa Jääskeläinen if (rc) 932f1105cc5SVesa Jääskeläinen return rc; 933f1105cc5SVesa Jääskeläinen } 934f1105cc5SVesa Jääskeläinen 93512253e9eSVesa Jääskeläinen inited: 93612253e9eSVesa Jääskeläinen /* Make sure SO PIN counters are zeroed */ 937f485be04SJens Wiklander token->db_main->flags &= ~(PKCS11_CKFT_SO_PIN_COUNT_LOW | 93812253e9eSVesa Jääskeläinen PKCS11_CKFT_SO_PIN_FINAL_TRY | 93912253e9eSVesa Jääskeläinen PKCS11_CKFT_SO_PIN_LOCKED | 94012253e9eSVesa Jääskeläinen PKCS11_CKFT_SO_PIN_TO_BE_CHANGED); 941f485be04SJens Wiklander token->db_main->so_pin_count = 0; 942f485be04SJens Wiklander 943f485be04SJens Wiklander TEE_MemMove(token->db_main->label, label, PKCS11_TOKEN_LABEL_SIZE); 944f485be04SJens Wiklander token->db_main->flags |= PKCS11_CKFT_TOKEN_INITIALIZED; 945f485be04SJens Wiklander /* Reset user PIN */ 946f485be04SJens Wiklander token->db_main->user_pin_salt = 0; 947f485be04SJens Wiklander token->db_main->flags &= ~(PKCS11_CKFT_USER_PIN_INITIALIZED | 948f485be04SJens Wiklander PKCS11_CKFT_USER_PIN_COUNT_LOW | 949f485be04SJens Wiklander PKCS11_CKFT_USER_PIN_FINAL_TRY | 950f485be04SJens Wiklander PKCS11_CKFT_USER_PIN_LOCKED | 951f485be04SJens Wiklander PKCS11_CKFT_USER_PIN_TO_BE_CHANGED); 952f485be04SJens Wiklander 953f485be04SJens Wiklander update_persistent_db(token); 954f485be04SJens Wiklander 9557f12c782SRobin van der Gracht /* Remove all persistent objects */ 9567f12c782SRobin van der Gracht while (!LIST_EMPTY(&token->object_list)) { 9577f12c782SRobin van der Gracht obj = LIST_FIRST(&token->object_list); 9587f12c782SRobin van der Gracht 9597f12c782SRobin van der Gracht /* Try twice otherwise panic! */ 9607f12c782SRobin van der Gracht if (unregister_persistent_object(token, obj->uuid) && 9617f12c782SRobin van der Gracht unregister_persistent_object(token, obj->uuid)) 9627f12c782SRobin van der Gracht TEE_Panic(0); 9637f12c782SRobin van der Gracht 9647f12c782SRobin van der Gracht cleanup_persistent_object(obj, token); 9657f12c782SRobin van der Gracht } 9667f12c782SRobin van der Gracht 967f485be04SJens Wiklander IMSG("PKCS11 token %"PRIu32": initialized", token_id); 968f485be04SJens Wiklander 969f485be04SJens Wiklander return PKCS11_CKR_OK; 970f485be04SJens Wiklander } 971e8dbd92cSJens Wiklander 972e8dbd92cSJens Wiklander static enum pkcs11_rc set_pin(struct pkcs11_session *session, 973e8dbd92cSJens Wiklander uint8_t *new_pin, size_t new_pin_size, 974e8dbd92cSJens Wiklander enum pkcs11_user_type user_type) 975e8dbd92cSJens Wiklander { 9761e497011SVesa Jääskeläinen struct ck_token *token = session->token; 977e8dbd92cSJens Wiklander enum pkcs11_rc rc = PKCS11_CKR_OK; 978e8dbd92cSJens Wiklander uint32_t flags_clear = 0; 979e8dbd92cSJens Wiklander uint32_t flags_set = 0; 980e8dbd92cSJens Wiklander 9811e497011SVesa Jääskeläinen if (token->db_main->flags & PKCS11_CKFT_WRITE_PROTECTED) 982e8dbd92cSJens Wiklander return PKCS11_CKR_TOKEN_WRITE_PROTECTED; 983e8dbd92cSJens Wiklander 984e8dbd92cSJens Wiklander if (!pkcs11_session_is_read_write(session)) 985e8dbd92cSJens Wiklander return PKCS11_CKR_SESSION_READ_ONLY; 986e8dbd92cSJens Wiklander 9871a27b197SVesa Jääskeläinen if (IS_ENABLED(CFG_PKCS11_TA_AUTH_TEE_IDENTITY) && 988920e0127SVesa Jääskeläinen (token->db_main->flags & 989920e0127SVesa Jääskeläinen PKCS11_CKFT_PROTECTED_AUTHENTICATION_PATH)) { 990920e0127SVesa Jääskeläinen rc = setup_identity_auth_from_pin(token, user_type, 991920e0127SVesa Jääskeläinen new_pin, new_pin_size); 992920e0127SVesa Jääskeläinen if (rc == PKCS11_CKR_OK) { 993920e0127SVesa Jääskeläinen goto update_db; 994920e0127SVesa Jääskeläinen } else if (rc == PKCS11_CKR_PIN_INVALID && 995920e0127SVesa Jääskeläinen !(token->db_main->flags & 996920e0127SVesa Jääskeläinen PKCS11_CKFT_USER_PIN_INITIALIZED)) { 997920e0127SVesa Jääskeläinen /* 998920e0127SVesa Jääskeläinen * PIN was not compatible with TEE Identity 999920e0127SVesa Jääskeläinen * Authentication syntax so let's assume it might be a 1000920e0127SVesa Jääskeläinen * new SO PIN to switch the authentication mode. 1001920e0127SVesa Jääskeläinen */ 1002920e0127SVesa Jääskeläinen 1003920e0127SVesa Jääskeläinen /* Update mode flag if all PIN checks pass */ 1004920e0127SVesa Jääskeläinen flags_clear |= 1005920e0127SVesa Jääskeläinen PKCS11_CKFT_PROTECTED_AUTHENTICATION_PATH; 1006920e0127SVesa Jääskeläinen } else { 10071a27b197SVesa Jääskeläinen return rc; 1008920e0127SVesa Jääskeläinen } 1009920e0127SVesa Jääskeläinen } else if ((user_type == PKCS11_CKU_SO) && !new_pin && 1010920e0127SVesa Jääskeläinen IS_ENABLED(CFG_PKCS11_TA_AUTH_TEE_IDENTITY) && 1011920e0127SVesa Jääskeläinen !(token->db_main->flags & 1012920e0127SVesa Jääskeläinen PKCS11_CKFT_USER_PIN_INITIALIZED)) { 1013920e0127SVesa Jääskeläinen /* 1014920e0127SVesa Jääskeläinen * Allow changing of token authentication mode before user pin 1015920e0127SVesa Jääskeläinen * has been initialized. 1016920e0127SVesa Jääskeläinen */ 1017920e0127SVesa Jääskeläinen 1018920e0127SVesa Jääskeläinen /* 1019920e0127SVesa Jääskeläinen * Set protected authentication path temporary until 1020920e0127SVesa Jääskeläinen * finalized. 1021920e0127SVesa Jääskeläinen */ 1022920e0127SVesa Jääskeläinen token->db_main->flags |= 1023920e0127SVesa Jääskeläinen PKCS11_CKFT_PROTECTED_AUTHENTICATION_PATH; 1024920e0127SVesa Jääskeläinen 1025920e0127SVesa Jääskeläinen /* 1026920e0127SVesa Jääskeläinen * Setup authentication from currently active TEE Client 1027920e0127SVesa Jääskeläinen * Identity. 1028920e0127SVesa Jääskeläinen */ 1029920e0127SVesa Jääskeläinen rc = setup_identity_auth_from_pin(token, PKCS11_CKU_SO, 1030920e0127SVesa Jääskeläinen NULL, 0); 1031920e0127SVesa Jääskeläinen if (rc) { 1032920e0127SVesa Jääskeläinen /* 1033920e0127SVesa Jääskeläinen * Failed to setup protected authentication path so 1034920e0127SVesa Jääskeläinen * clear the temporary flag. 1035920e0127SVesa Jääskeläinen */ 1036920e0127SVesa Jääskeläinen token->db_main->flags &= 1037920e0127SVesa Jääskeläinen ~PKCS11_CKFT_PROTECTED_AUTHENTICATION_PATH; 1038920e0127SVesa Jääskeläinen return rc; 1039920e0127SVesa Jääskeläinen } 10401a27b197SVesa Jääskeläinen 10411a27b197SVesa Jääskeläinen goto update_db; 10421a27b197SVesa Jääskeläinen } 10431a27b197SVesa Jääskeläinen 1044e8dbd92cSJens Wiklander if (new_pin_size < PKCS11_TOKEN_PIN_SIZE_MIN || 1045e8dbd92cSJens Wiklander new_pin_size > PKCS11_TOKEN_PIN_SIZE_MAX) 1046e8dbd92cSJens Wiklander return PKCS11_CKR_PIN_LEN_RANGE; 1047e8dbd92cSJens Wiklander 1048e8dbd92cSJens Wiklander switch (user_type) { 1049e8dbd92cSJens Wiklander case PKCS11_CKU_SO: 1050e8dbd92cSJens Wiklander rc = hash_pin(user_type, new_pin, new_pin_size, 10511e497011SVesa Jääskeläinen &token->db_main->so_pin_salt, 10521e497011SVesa Jääskeläinen token->db_main->so_pin_hash); 1053e8dbd92cSJens Wiklander if (rc) 1054e8dbd92cSJens Wiklander return rc; 10551e497011SVesa Jääskeläinen token->db_main->so_pin_count = 0; 1056920e0127SVesa Jääskeläinen flags_clear |= PKCS11_CKFT_SO_PIN_COUNT_LOW | 1057e8dbd92cSJens Wiklander PKCS11_CKFT_SO_PIN_FINAL_TRY | 1058e8dbd92cSJens Wiklander PKCS11_CKFT_SO_PIN_LOCKED | 1059e8dbd92cSJens Wiklander PKCS11_CKFT_SO_PIN_TO_BE_CHANGED; 1060e8dbd92cSJens Wiklander break; 1061e8dbd92cSJens Wiklander case PKCS11_CKU_USER: 1062e8dbd92cSJens Wiklander rc = hash_pin(user_type, new_pin, new_pin_size, 10631e497011SVesa Jääskeläinen &token->db_main->user_pin_salt, 10641e497011SVesa Jääskeläinen token->db_main->user_pin_hash); 1065e8dbd92cSJens Wiklander if (rc) 1066e8dbd92cSJens Wiklander return rc; 10671e497011SVesa Jääskeläinen token->db_main->user_pin_count = 0; 1068920e0127SVesa Jääskeläinen flags_clear |= PKCS11_CKFT_USER_PIN_COUNT_LOW | 1069e8dbd92cSJens Wiklander PKCS11_CKFT_USER_PIN_FINAL_TRY | 1070e8dbd92cSJens Wiklander PKCS11_CKFT_USER_PIN_LOCKED | 1071e8dbd92cSJens Wiklander PKCS11_CKFT_USER_PIN_TO_BE_CHANGED; 1072920e0127SVesa Jääskeläinen flags_set |= PKCS11_CKFT_USER_PIN_INITIALIZED; 1073e8dbd92cSJens Wiklander break; 1074e8dbd92cSJens Wiklander default: 1075e8dbd92cSJens Wiklander return PKCS11_CKR_FUNCTION_FAILED; 1076e8dbd92cSJens Wiklander } 1077e8dbd92cSJens Wiklander 10781a27b197SVesa Jääskeläinen update_db: 10791e497011SVesa Jääskeläinen token->db_main->flags &= ~flags_clear; 10801e497011SVesa Jääskeläinen token->db_main->flags |= flags_set; 1081e8dbd92cSJens Wiklander 10821e497011SVesa Jääskeläinen update_persistent_db(token); 1083e8dbd92cSJens Wiklander 1084e8dbd92cSJens Wiklander return PKCS11_CKR_OK; 1085e8dbd92cSJens Wiklander } 1086e8dbd92cSJens Wiklander 10874daf39b3SJens Wiklander enum pkcs11_rc entry_ck_init_pin(struct pkcs11_client *client, 1088e8dbd92cSJens Wiklander uint32_t ptypes, TEE_Param *params) 1089e8dbd92cSJens Wiklander { 1090e8dbd92cSJens Wiklander const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 1091e8dbd92cSJens Wiklander TEE_PARAM_TYPE_NONE, 1092e8dbd92cSJens Wiklander TEE_PARAM_TYPE_NONE, 1093e8dbd92cSJens Wiklander TEE_PARAM_TYPE_NONE); 1094e8dbd92cSJens Wiklander struct pkcs11_session *session = NULL; 1095e8dbd92cSJens Wiklander enum pkcs11_rc rc = PKCS11_CKR_OK; 1096e8dbd92cSJens Wiklander struct serialargs ctrlargs = { }; 1097e8dbd92cSJens Wiklander TEE_Param *ctrl = params; 1098e8dbd92cSJens Wiklander uint32_t pin_size = 0; 1099e8dbd92cSJens Wiklander void *pin = NULL; 1100e8dbd92cSJens Wiklander 1101e8dbd92cSJens Wiklander if (!client || ptypes != exp_pt) 1102e8dbd92cSJens Wiklander return PKCS11_CKR_ARGUMENTS_BAD; 1103e8dbd92cSJens Wiklander 1104e8dbd92cSJens Wiklander serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 1105e8dbd92cSJens Wiklander 1106f40f331fSEtienne Carriere rc = serialargs_get_session_from_handle(&ctrlargs, client, &session); 1107e8dbd92cSJens Wiklander if (rc) 1108e8dbd92cSJens Wiklander return rc; 1109e8dbd92cSJens Wiklander 1110e8dbd92cSJens Wiklander rc = serialargs_get(&ctrlargs, &pin_size, sizeof(uint32_t)); 1111e8dbd92cSJens Wiklander if (rc) 1112e8dbd92cSJens Wiklander return rc; 1113e8dbd92cSJens Wiklander 1114e8dbd92cSJens Wiklander rc = serialargs_get_ptr(&ctrlargs, &pin, pin_size); 1115e8dbd92cSJens Wiklander if (rc) 1116e8dbd92cSJens Wiklander return rc; 1117e8dbd92cSJens Wiklander 1118e8dbd92cSJens Wiklander if (serialargs_remaining_bytes(&ctrlargs)) 1119e8dbd92cSJens Wiklander return PKCS11_CKR_ARGUMENTS_BAD; 1120e8dbd92cSJens Wiklander 1121e8dbd92cSJens Wiklander if (!pkcs11_session_is_so(session)) 1122e8dbd92cSJens Wiklander return PKCS11_CKR_USER_NOT_LOGGED_IN; 1123e8dbd92cSJens Wiklander 1124e8dbd92cSJens Wiklander assert(session->token->db_main->flags & PKCS11_CKFT_TOKEN_INITIALIZED); 1125e8dbd92cSJens Wiklander 1126f40f331fSEtienne Carriere IMSG("PKCS11 session %"PRIu32": init PIN", session->handle); 1127e8dbd92cSJens Wiklander 1128e8dbd92cSJens Wiklander return set_pin(session, pin, pin_size, PKCS11_CKU_USER); 1129e8dbd92cSJens Wiklander } 11301dbb91e7SJens Wiklander 11314daf39b3SJens Wiklander static enum pkcs11_rc check_so_pin(struct pkcs11_session *session, 11321dbb91e7SJens Wiklander uint8_t *pin, size_t pin_size) 11331dbb91e7SJens Wiklander { 11341dbb91e7SJens Wiklander struct ck_token *token = session->token; 11351dbb91e7SJens Wiklander enum pkcs11_rc rc = PKCS11_CKR_OK; 11361dbb91e7SJens Wiklander 11371dbb91e7SJens Wiklander assert(token->db_main->flags & PKCS11_CKFT_TOKEN_INITIALIZED); 11381dbb91e7SJens Wiklander 11391a27b197SVesa Jääskeläinen if (IS_ENABLED(CFG_PKCS11_TA_AUTH_TEE_IDENTITY) && 11401a27b197SVesa Jääskeläinen token->db_main->flags & PKCS11_CKFT_PROTECTED_AUTHENTICATION_PATH) 11411a27b197SVesa Jääskeläinen return verify_identity_auth(token, PKCS11_CKU_SO); 11421a27b197SVesa Jääskeläinen 11431dbb91e7SJens Wiklander if (token->db_main->flags & PKCS11_CKFT_SO_PIN_LOCKED) 11441dbb91e7SJens Wiklander return PKCS11_CKR_PIN_LOCKED; 11451dbb91e7SJens Wiklander 11461dbb91e7SJens Wiklander rc = verify_pin(PKCS11_CKU_SO, pin, pin_size, 11471dbb91e7SJens Wiklander token->db_main->so_pin_salt, 11481dbb91e7SJens Wiklander token->db_main->so_pin_hash); 11491dbb91e7SJens Wiklander if (rc) { 11501dbb91e7SJens Wiklander unsigned int pin_count = 0; 11511dbb91e7SJens Wiklander 11521dbb91e7SJens Wiklander if (rc != PKCS11_CKR_PIN_INCORRECT) 11531dbb91e7SJens Wiklander return rc; 11541dbb91e7SJens Wiklander 11551dbb91e7SJens Wiklander token->db_main->flags |= PKCS11_CKFT_SO_PIN_COUNT_LOW; 11561dbb91e7SJens Wiklander token->db_main->so_pin_count++; 11571dbb91e7SJens Wiklander 11581dbb91e7SJens Wiklander pin_count = token->db_main->so_pin_count; 11591dbb91e7SJens Wiklander if (pin_count == PKCS11_TOKEN_SO_PIN_COUNT_MAX - 1) 11601dbb91e7SJens Wiklander token->db_main->flags |= PKCS11_CKFT_SO_PIN_FINAL_TRY; 11611dbb91e7SJens Wiklander if (pin_count == PKCS11_TOKEN_SO_PIN_COUNT_MAX) 11621dbb91e7SJens Wiklander token->db_main->flags |= PKCS11_CKFT_SO_PIN_LOCKED; 11631dbb91e7SJens Wiklander 11641dbb91e7SJens Wiklander update_persistent_db(token); 11651dbb91e7SJens Wiklander 11661dbb91e7SJens Wiklander if (token->db_main->flags & PKCS11_CKFT_SO_PIN_LOCKED) 11671dbb91e7SJens Wiklander return PKCS11_CKR_PIN_LOCKED; 11681dbb91e7SJens Wiklander 11691dbb91e7SJens Wiklander return PKCS11_CKR_PIN_INCORRECT; 11701dbb91e7SJens Wiklander } 11711dbb91e7SJens Wiklander 11721dbb91e7SJens Wiklander if (token->db_main->so_pin_count) { 11731dbb91e7SJens Wiklander token->db_main->so_pin_count = 0; 11741dbb91e7SJens Wiklander 11751dbb91e7SJens Wiklander update_persistent_db(token); 11761dbb91e7SJens Wiklander } 11771dbb91e7SJens Wiklander 11781dbb91e7SJens Wiklander if (token->db_main->flags & (PKCS11_CKFT_SO_PIN_COUNT_LOW | 11791dbb91e7SJens Wiklander PKCS11_CKFT_SO_PIN_FINAL_TRY)) { 11801dbb91e7SJens Wiklander token->db_main->flags &= ~(PKCS11_CKFT_SO_PIN_COUNT_LOW | 11811dbb91e7SJens Wiklander PKCS11_CKFT_SO_PIN_FINAL_TRY); 11821dbb91e7SJens Wiklander 11831dbb91e7SJens Wiklander update_persistent_db(token); 11841dbb91e7SJens Wiklander } 11851dbb91e7SJens Wiklander 11861dbb91e7SJens Wiklander return PKCS11_CKR_OK; 11871dbb91e7SJens Wiklander } 11881dbb91e7SJens Wiklander 11894daf39b3SJens Wiklander static enum pkcs11_rc check_user_pin(struct pkcs11_session *session, 11901dbb91e7SJens Wiklander uint8_t *pin, size_t pin_size) 11911dbb91e7SJens Wiklander { 11921dbb91e7SJens Wiklander struct ck_token *token = session->token; 11931dbb91e7SJens Wiklander enum pkcs11_rc rc = PKCS11_CKR_OK; 11941dbb91e7SJens Wiklander 11951a27b197SVesa Jääskeläinen if (IS_ENABLED(CFG_PKCS11_TA_AUTH_TEE_IDENTITY) && 11961a27b197SVesa Jääskeläinen token->db_main->flags & PKCS11_CKFT_PROTECTED_AUTHENTICATION_PATH) 11971a27b197SVesa Jääskeläinen return verify_identity_auth(token, PKCS11_CKU_USER); 11981a27b197SVesa Jääskeläinen 11991dbb91e7SJens Wiklander if (!token->db_main->user_pin_salt) 12001dbb91e7SJens Wiklander return PKCS11_CKR_USER_PIN_NOT_INITIALIZED; 12011dbb91e7SJens Wiklander 12021dbb91e7SJens Wiklander if (token->db_main->flags & PKCS11_CKFT_USER_PIN_LOCKED) 12031dbb91e7SJens Wiklander return PKCS11_CKR_PIN_LOCKED; 12041dbb91e7SJens Wiklander 12051dbb91e7SJens Wiklander rc = verify_pin(PKCS11_CKU_USER, pin, pin_size, 12061dbb91e7SJens Wiklander token->db_main->user_pin_salt, 12071dbb91e7SJens Wiklander token->db_main->user_pin_hash); 12081dbb91e7SJens Wiklander if (rc) { 12091dbb91e7SJens Wiklander unsigned int pin_count = 0; 12101dbb91e7SJens Wiklander 12111dbb91e7SJens Wiklander if (rc != PKCS11_CKR_PIN_INCORRECT) 12121dbb91e7SJens Wiklander return rc; 12131dbb91e7SJens Wiklander 12141dbb91e7SJens Wiklander token->db_main->flags |= PKCS11_CKFT_USER_PIN_COUNT_LOW; 12151dbb91e7SJens Wiklander token->db_main->user_pin_count++; 12161dbb91e7SJens Wiklander 12171dbb91e7SJens Wiklander pin_count = token->db_main->user_pin_count; 12181dbb91e7SJens Wiklander if (pin_count == PKCS11_TOKEN_USER_PIN_COUNT_MAX - 1) 12191dbb91e7SJens Wiklander token->db_main->flags |= PKCS11_CKFT_USER_PIN_FINAL_TRY; 12201dbb91e7SJens Wiklander if (pin_count == PKCS11_TOKEN_USER_PIN_COUNT_MAX) 12211dbb91e7SJens Wiklander token->db_main->flags |= PKCS11_CKFT_USER_PIN_LOCKED; 12221dbb91e7SJens Wiklander 12231dbb91e7SJens Wiklander update_persistent_db(token); 12241dbb91e7SJens Wiklander 12251dbb91e7SJens Wiklander if (token->db_main->flags & PKCS11_CKFT_USER_PIN_LOCKED) 12261dbb91e7SJens Wiklander return PKCS11_CKR_PIN_LOCKED; 12271dbb91e7SJens Wiklander 12281dbb91e7SJens Wiklander return PKCS11_CKR_PIN_INCORRECT; 12291dbb91e7SJens Wiklander } 12301dbb91e7SJens Wiklander 12311dbb91e7SJens Wiklander if (token->db_main->user_pin_count) { 12321dbb91e7SJens Wiklander token->db_main->user_pin_count = 0; 12331dbb91e7SJens Wiklander 12341dbb91e7SJens Wiklander update_persistent_db(token); 12351dbb91e7SJens Wiklander } 12361dbb91e7SJens Wiklander 12371dbb91e7SJens Wiklander if (token->db_main->flags & (PKCS11_CKFT_USER_PIN_COUNT_LOW | 12381dbb91e7SJens Wiklander PKCS11_CKFT_USER_PIN_FINAL_TRY)) { 12391dbb91e7SJens Wiklander token->db_main->flags &= ~(PKCS11_CKFT_USER_PIN_COUNT_LOW | 12401dbb91e7SJens Wiklander PKCS11_CKFT_USER_PIN_FINAL_TRY); 12411dbb91e7SJens Wiklander 12421dbb91e7SJens Wiklander update_persistent_db(token); 12431dbb91e7SJens Wiklander } 12441dbb91e7SJens Wiklander 12451dbb91e7SJens Wiklander return PKCS11_CKR_OK; 12461dbb91e7SJens Wiklander } 12471dbb91e7SJens Wiklander 12484daf39b3SJens Wiklander enum pkcs11_rc entry_ck_set_pin(struct pkcs11_client *client, 12491dbb91e7SJens Wiklander uint32_t ptypes, TEE_Param *params) 12501dbb91e7SJens Wiklander { 12511dbb91e7SJens Wiklander const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 12521dbb91e7SJens Wiklander TEE_PARAM_TYPE_NONE, 12531dbb91e7SJens Wiklander TEE_PARAM_TYPE_NONE, 12541dbb91e7SJens Wiklander TEE_PARAM_TYPE_NONE); 12551dbb91e7SJens Wiklander struct pkcs11_session *session = NULL; 12561dbb91e7SJens Wiklander enum pkcs11_rc rc = PKCS11_CKR_OK; 12571dbb91e7SJens Wiklander struct serialargs ctrlargs = { }; 12581dbb91e7SJens Wiklander uint32_t old_pin_size = 0; 12591dbb91e7SJens Wiklander TEE_Param *ctrl = params; 12601dbb91e7SJens Wiklander uint32_t pin_size = 0; 12611dbb91e7SJens Wiklander void *old_pin = NULL; 12621dbb91e7SJens Wiklander void *pin = NULL; 12631dbb91e7SJens Wiklander 12641dbb91e7SJens Wiklander if (!client || ptypes != exp_pt) 12651dbb91e7SJens Wiklander return PKCS11_CKR_ARGUMENTS_BAD; 12661dbb91e7SJens Wiklander 12671dbb91e7SJens Wiklander serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 12681dbb91e7SJens Wiklander 1269f40f331fSEtienne Carriere rc = serialargs_get_session_from_handle(&ctrlargs, client, &session); 12701dbb91e7SJens Wiklander if (rc) 12711dbb91e7SJens Wiklander return rc; 12721dbb91e7SJens Wiklander 12731dbb91e7SJens Wiklander rc = serialargs_get(&ctrlargs, &old_pin_size, sizeof(uint32_t)); 12741dbb91e7SJens Wiklander if (rc) 12751dbb91e7SJens Wiklander return rc; 12761dbb91e7SJens Wiklander 12771dbb91e7SJens Wiklander rc = serialargs_get(&ctrlargs, &pin_size, sizeof(uint32_t)); 12781dbb91e7SJens Wiklander if (rc) 12791dbb91e7SJens Wiklander return rc; 12801dbb91e7SJens Wiklander 12811dbb91e7SJens Wiklander rc = serialargs_get_ptr(&ctrlargs, &old_pin, old_pin_size); 12821dbb91e7SJens Wiklander if (rc) 12831dbb91e7SJens Wiklander return rc; 12841dbb91e7SJens Wiklander 12851dbb91e7SJens Wiklander rc = serialargs_get_ptr(&ctrlargs, &pin, pin_size); 12861dbb91e7SJens Wiklander if (rc) 12871dbb91e7SJens Wiklander return rc; 12881dbb91e7SJens Wiklander 12891dbb91e7SJens Wiklander if (serialargs_remaining_bytes(&ctrlargs)) 12901dbb91e7SJens Wiklander return PKCS11_CKR_ARGUMENTS_BAD; 12911dbb91e7SJens Wiklander 12921dbb91e7SJens Wiklander if (!pkcs11_session_is_read_write(session)) 12931dbb91e7SJens Wiklander return PKCS11_CKR_SESSION_READ_ONLY; 12941dbb91e7SJens Wiklander 12951dbb91e7SJens Wiklander if (pkcs11_session_is_so(session)) { 12961dbb91e7SJens Wiklander if (!(session->token->db_main->flags & 12971dbb91e7SJens Wiklander PKCS11_CKFT_TOKEN_INITIALIZED)) 12981dbb91e7SJens Wiklander return PKCS11_CKR_GENERAL_ERROR; 12991dbb91e7SJens Wiklander 13001dbb91e7SJens Wiklander rc = check_so_pin(session, old_pin, old_pin_size); 13011dbb91e7SJens Wiklander if (rc) 13021dbb91e7SJens Wiklander return rc; 13031dbb91e7SJens Wiklander 1304f40f331fSEtienne Carriere IMSG("PKCS11 session %"PRIu32": set PIN", session->handle); 13051dbb91e7SJens Wiklander 13061dbb91e7SJens Wiklander return set_pin(session, pin, pin_size, PKCS11_CKU_SO); 13071dbb91e7SJens Wiklander } 13081dbb91e7SJens Wiklander 13091dbb91e7SJens Wiklander if (!(session->token->db_main->flags & 13101dbb91e7SJens Wiklander PKCS11_CKFT_USER_PIN_INITIALIZED)) 13111dbb91e7SJens Wiklander return PKCS11_CKR_GENERAL_ERROR; 13121dbb91e7SJens Wiklander 13131dbb91e7SJens Wiklander rc = check_user_pin(session, old_pin, old_pin_size); 13141dbb91e7SJens Wiklander if (rc) 13151dbb91e7SJens Wiklander return rc; 13161dbb91e7SJens Wiklander 1317f40f331fSEtienne Carriere IMSG("PKCS11 session %"PRIu32": set PIN", session->handle); 13181dbb91e7SJens Wiklander 13191dbb91e7SJens Wiklander return set_pin(session, pin, pin_size, PKCS11_CKU_USER); 13201dbb91e7SJens Wiklander } 1321f7cc36c0SJens Wiklander 1322f7cc36c0SJens Wiklander static void session_login_user(struct pkcs11_session *session) 1323f7cc36c0SJens Wiklander { 1324f7cc36c0SJens Wiklander struct pkcs11_client *client = session->client; 1325f7cc36c0SJens Wiklander struct pkcs11_session *sess = NULL; 1326f7cc36c0SJens Wiklander 1327f7cc36c0SJens Wiklander TAILQ_FOREACH(sess, &client->session_list, link) { 1328f7cc36c0SJens Wiklander if (sess->token != session->token) 1329f7cc36c0SJens Wiklander continue; 1330f7cc36c0SJens Wiklander 1331f7cc36c0SJens Wiklander if (pkcs11_session_is_read_write(sess)) 1332f7cc36c0SJens Wiklander sess->state = PKCS11_CKS_RW_USER_FUNCTIONS; 1333f7cc36c0SJens Wiklander else 1334f7cc36c0SJens Wiklander sess->state = PKCS11_CKS_RO_USER_FUNCTIONS; 1335f7cc36c0SJens Wiklander } 1336f7cc36c0SJens Wiklander } 1337f7cc36c0SJens Wiklander 1338f7cc36c0SJens Wiklander static void session_login_so(struct pkcs11_session *session) 1339f7cc36c0SJens Wiklander { 1340f7cc36c0SJens Wiklander struct pkcs11_client *client = session->client; 1341f7cc36c0SJens Wiklander struct pkcs11_session *sess = NULL; 1342f7cc36c0SJens Wiklander 1343f7cc36c0SJens Wiklander TAILQ_FOREACH(sess, &client->session_list, link) { 1344f7cc36c0SJens Wiklander if (sess->token != session->token) 1345f7cc36c0SJens Wiklander continue; 1346f7cc36c0SJens Wiklander 1347f7cc36c0SJens Wiklander if (pkcs11_session_is_read_write(sess)) 1348f7cc36c0SJens Wiklander sess->state = PKCS11_CKS_RW_SO_FUNCTIONS; 1349f7cc36c0SJens Wiklander else 1350f7cc36c0SJens Wiklander TEE_Panic(0); 1351f7cc36c0SJens Wiklander } 1352f7cc36c0SJens Wiklander } 1353f7cc36c0SJens Wiklander 1354f7cc36c0SJens Wiklander static void session_logout(struct pkcs11_session *session) 1355f7cc36c0SJens Wiklander { 1356f7cc36c0SJens Wiklander struct pkcs11_client *client = session->client; 1357f7cc36c0SJens Wiklander struct pkcs11_session *sess = NULL; 1358f7cc36c0SJens Wiklander 1359f7cc36c0SJens Wiklander TAILQ_FOREACH(sess, &client->session_list, link) { 136089735787SRuchika Gupta struct pkcs11_object *obj = NULL; 13613bf0e097SRuchika Gupta struct pkcs11_object *tobj = NULL; 136289735787SRuchika Gupta uint32_t handle = 0; 136389735787SRuchika Gupta 1364f7cc36c0SJens Wiklander if (sess->token != session->token) 1365f7cc36c0SJens Wiklander continue; 1366f7cc36c0SJens Wiklander 136789735787SRuchika Gupta release_active_processing(session); 136889735787SRuchika Gupta 136989735787SRuchika Gupta /* Destroy private session objects */ 13703bf0e097SRuchika Gupta LIST_FOREACH_SAFE(obj, &sess->object_list, link, tobj) { 137189735787SRuchika Gupta if (object_is_private(obj->attributes)) 137289735787SRuchika Gupta destroy_object(sess, obj, true); 137389735787SRuchika Gupta } 137489735787SRuchika Gupta 137589735787SRuchika Gupta /* 137689735787SRuchika Gupta * Remove handle of token private objects from 137789735787SRuchika Gupta * sessions object_handle_db 137889735787SRuchika Gupta */ 137989735787SRuchika Gupta LIST_FOREACH(obj, &session->token->object_list, link) { 138089735787SRuchika Gupta handle = pkcs11_object2handle(obj, session); 138189735787SRuchika Gupta 138289735787SRuchika Gupta if (handle && object_is_private(obj->attributes)) 1383bc555ee0SVesa Jääskeläinen handle_put(get_object_handle_db(sess), handle); 138489735787SRuchika Gupta } 138589735787SRuchika Gupta 138689735787SRuchika Gupta release_session_find_obj_context(session); 138789735787SRuchika Gupta 1388f7cc36c0SJens Wiklander if (pkcs11_session_is_read_write(sess)) 1389f7cc36c0SJens Wiklander sess->state = PKCS11_CKS_RW_PUBLIC_SESSION; 1390f7cc36c0SJens Wiklander else 1391f7cc36c0SJens Wiklander sess->state = PKCS11_CKS_RO_PUBLIC_SESSION; 1392f7cc36c0SJens Wiklander } 1393f7cc36c0SJens Wiklander } 1394f7cc36c0SJens Wiklander 13954daf39b3SJens Wiklander enum pkcs11_rc entry_ck_login(struct pkcs11_client *client, 1396f7cc36c0SJens Wiklander uint32_t ptypes, TEE_Param *params) 1397f7cc36c0SJens Wiklander { 1398f7cc36c0SJens Wiklander const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 1399f7cc36c0SJens Wiklander TEE_PARAM_TYPE_NONE, 1400f7cc36c0SJens Wiklander TEE_PARAM_TYPE_NONE, 1401f7cc36c0SJens Wiklander TEE_PARAM_TYPE_NONE); 1402f7cc36c0SJens Wiklander struct pkcs11_session *session = NULL; 1403f7cc36c0SJens Wiklander struct pkcs11_session *sess = NULL; 1404f7cc36c0SJens Wiklander enum pkcs11_rc rc = PKCS11_CKR_OK; 1405f7cc36c0SJens Wiklander struct serialargs ctrlargs = { }; 1406f7cc36c0SJens Wiklander TEE_Param *ctrl = params; 1407f7cc36c0SJens Wiklander uint32_t user_type = 0; 1408f7cc36c0SJens Wiklander uint32_t pin_size = 0; 1409f7cc36c0SJens Wiklander void *pin = NULL; 1410f7cc36c0SJens Wiklander 1411f7cc36c0SJens Wiklander if (!client || ptypes != exp_pt) 1412f7cc36c0SJens Wiklander return PKCS11_CKR_ARGUMENTS_BAD; 1413f7cc36c0SJens Wiklander 1414f7cc36c0SJens Wiklander serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 1415f7cc36c0SJens Wiklander 1416f40f331fSEtienne Carriere rc = serialargs_get_session_from_handle(&ctrlargs, client, &session); 1417f7cc36c0SJens Wiklander if (rc) 1418f7cc36c0SJens Wiklander return rc; 1419f7cc36c0SJens Wiklander 1420f7cc36c0SJens Wiklander rc = serialargs_get(&ctrlargs, &user_type, sizeof(uint32_t)); 1421f7cc36c0SJens Wiklander if (rc) 1422f7cc36c0SJens Wiklander return rc; 1423f7cc36c0SJens Wiklander 1424f7cc36c0SJens Wiklander rc = serialargs_get(&ctrlargs, &pin_size, sizeof(uint32_t)); 1425f7cc36c0SJens Wiklander if (rc) 1426f7cc36c0SJens Wiklander return rc; 1427f7cc36c0SJens Wiklander 1428f7cc36c0SJens Wiklander rc = serialargs_get_ptr(&ctrlargs, &pin, pin_size); 1429f7cc36c0SJens Wiklander if (rc) 1430f7cc36c0SJens Wiklander return rc; 1431f7cc36c0SJens Wiklander 1432f7cc36c0SJens Wiklander if (serialargs_remaining_bytes(&ctrlargs)) 1433f7cc36c0SJens Wiklander return PKCS11_CKR_ARGUMENTS_BAD; 1434f7cc36c0SJens Wiklander 1435f7cc36c0SJens Wiklander switch (user_type) { 1436f7cc36c0SJens Wiklander case PKCS11_CKU_SO: 1437f7cc36c0SJens Wiklander if (pkcs11_session_is_so(session)) 1438f7cc36c0SJens Wiklander return PKCS11_CKR_USER_ALREADY_LOGGED_IN; 1439f7cc36c0SJens Wiklander 1440f7cc36c0SJens Wiklander if (pkcs11_session_is_user(session)) 1441f7cc36c0SJens Wiklander return PKCS11_CKR_USER_ANOTHER_ALREADY_LOGGED_IN; 1442f7cc36c0SJens Wiklander 1443f7cc36c0SJens Wiklander TAILQ_FOREACH(sess, &client->session_list, link) 1444f7cc36c0SJens Wiklander if (sess->token == session->token && 1445f7cc36c0SJens Wiklander !pkcs11_session_is_read_write(sess)) 1446f7cc36c0SJens Wiklander return PKCS11_CKR_SESSION_READ_ONLY_EXISTS; 1447f7cc36c0SJens Wiklander 1448f7cc36c0SJens Wiklander /* 1449f7cc36c0SJens Wiklander * This is the point where we could check if another client 1450f7cc36c0SJens Wiklander * has another user or SO logged in. 1451f7cc36c0SJens Wiklander * 1452f7cc36c0SJens Wiklander * The spec says: 1453f7cc36c0SJens Wiklander * CKR_USER_TOO_MANY_TYPES: An attempt was made to have 1454f7cc36c0SJens Wiklander * more distinct users simultaneously logged into the token 1455f7cc36c0SJens Wiklander * than the token and/or library permits. For example, if 1456f7cc36c0SJens Wiklander * some application has an open SO session, and another 1457f7cc36c0SJens Wiklander * application attempts to log the normal user into a 1458f7cc36c0SJens Wiklander * session, the attempt may return this error. It is not 1459f7cc36c0SJens Wiklander * required to, however. Only if the simultaneous distinct 1460f7cc36c0SJens Wiklander * users cannot be supported does C_Login have to return 1461f7cc36c0SJens Wiklander * this value. Note that this error code generalizes to 1462f7cc36c0SJens Wiklander * true multi-user tokens. 1463f7cc36c0SJens Wiklander * 1464f7cc36c0SJens Wiklander * So it's permitted to have another user or SO logged in 1465f7cc36c0SJens Wiklander * from another client. 1466f7cc36c0SJens Wiklander */ 1467f7cc36c0SJens Wiklander 1468f7cc36c0SJens Wiklander rc = check_so_pin(session, pin, pin_size); 1469f7cc36c0SJens Wiklander if (!rc) 1470f7cc36c0SJens Wiklander session_login_so(session); 1471f7cc36c0SJens Wiklander 1472f7cc36c0SJens Wiklander break; 1473f7cc36c0SJens Wiklander 1474f7cc36c0SJens Wiklander case PKCS11_CKU_USER: 1475f7cc36c0SJens Wiklander if (pkcs11_session_is_so(session)) 1476f7cc36c0SJens Wiklander return PKCS11_CKR_USER_ANOTHER_ALREADY_LOGGED_IN; 1477f7cc36c0SJens Wiklander 1478f7cc36c0SJens Wiklander if (pkcs11_session_is_user(session)) 1479f7cc36c0SJens Wiklander return PKCS11_CKR_USER_ALREADY_LOGGED_IN; 1480f7cc36c0SJens Wiklander 1481f7cc36c0SJens Wiklander /* 1482f7cc36c0SJens Wiklander * This is the point where we could check if another client 1483f7cc36c0SJens Wiklander * has another user or SO logged in. 1484f7cc36c0SJens Wiklander * See comment on CKR_USER_TOO_MANY_TYPES above. 1485f7cc36c0SJens Wiklander */ 1486f7cc36c0SJens Wiklander 1487f7cc36c0SJens Wiklander rc = check_user_pin(session, pin, pin_size); 1488f7cc36c0SJens Wiklander if (!rc) 1489f7cc36c0SJens Wiklander session_login_user(session); 1490f7cc36c0SJens Wiklander 1491f7cc36c0SJens Wiklander break; 1492f7cc36c0SJens Wiklander 1493f7cc36c0SJens Wiklander case PKCS11_CKU_CONTEXT_SPECIFIC: 1494f7cc36c0SJens Wiklander return PKCS11_CKR_OPERATION_NOT_INITIALIZED; 1495f7cc36c0SJens Wiklander 1496f7cc36c0SJens Wiklander default: 1497f7cc36c0SJens Wiklander return PKCS11_CKR_USER_TYPE_INVALID; 1498f7cc36c0SJens Wiklander } 1499f7cc36c0SJens Wiklander 1500f7cc36c0SJens Wiklander if (!rc) 1501f40f331fSEtienne Carriere IMSG("PKCS11 session %"PRIu32": login", session->handle); 1502f7cc36c0SJens Wiklander 1503f7cc36c0SJens Wiklander return rc; 1504f7cc36c0SJens Wiklander } 1505f7cc36c0SJens Wiklander 15064daf39b3SJens Wiklander enum pkcs11_rc entry_ck_logout(struct pkcs11_client *client, 1507f7cc36c0SJens Wiklander uint32_t ptypes, TEE_Param *params) 1508f7cc36c0SJens Wiklander { 1509f7cc36c0SJens Wiklander const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 1510f7cc36c0SJens Wiklander TEE_PARAM_TYPE_NONE, 1511f7cc36c0SJens Wiklander TEE_PARAM_TYPE_NONE, 1512f7cc36c0SJens Wiklander TEE_PARAM_TYPE_NONE); 1513f7cc36c0SJens Wiklander struct pkcs11_session *session = NULL; 1514f7cc36c0SJens Wiklander enum pkcs11_rc rc = PKCS11_CKR_OK; 1515f7cc36c0SJens Wiklander struct serialargs ctrlargs = { }; 1516f7cc36c0SJens Wiklander TEE_Param *ctrl = params; 1517f7cc36c0SJens Wiklander 1518f7cc36c0SJens Wiklander if (!client || ptypes != exp_pt) 1519f7cc36c0SJens Wiklander return PKCS11_CKR_ARGUMENTS_BAD; 1520f7cc36c0SJens Wiklander 1521f7cc36c0SJens Wiklander serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 1522f7cc36c0SJens Wiklander 1523f40f331fSEtienne Carriere rc = serialargs_get_session_from_handle(&ctrlargs, client, &session); 1524f7cc36c0SJens Wiklander if (rc) 1525f7cc36c0SJens Wiklander return rc; 1526f7cc36c0SJens Wiklander 1527f7cc36c0SJens Wiklander if (serialargs_remaining_bytes(&ctrlargs)) 1528f7cc36c0SJens Wiklander return PKCS11_CKR_ARGUMENTS_BAD; 1529f7cc36c0SJens Wiklander 1530f7cc36c0SJens Wiklander if (pkcs11_session_is_public(session)) 1531f7cc36c0SJens Wiklander return PKCS11_CKR_USER_NOT_LOGGED_IN; 1532f7cc36c0SJens Wiklander 1533f7cc36c0SJens Wiklander session_logout(session); 1534f7cc36c0SJens Wiklander 1535f40f331fSEtienne Carriere IMSG("PKCS11 session %"PRIu32": logout", session->handle); 1536f7cc36c0SJens Wiklander 1537f7cc36c0SJens Wiklander return PKCS11_CKR_OK; 1538f7cc36c0SJens Wiklander } 153922587dc4SVesa Jääskeläinen 154022587dc4SVesa Jääskeläinen static TEE_Result seed_rng_pool(void *seed, size_t length) 154122587dc4SVesa Jääskeläinen { 154222587dc4SVesa Jääskeläinen static const TEE_UUID system_uuid = PTA_SYSTEM_UUID; 154322587dc4SVesa Jääskeläinen uint32_t param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, 154422587dc4SVesa Jääskeläinen TEE_PARAM_TYPE_NONE, 154522587dc4SVesa Jääskeläinen TEE_PARAM_TYPE_NONE, 154622587dc4SVesa Jääskeläinen TEE_PARAM_TYPE_NONE); 154722587dc4SVesa Jääskeläinen TEE_Param params[TEE_NUM_PARAMS] = { }; 154822587dc4SVesa Jääskeläinen TEE_TASessionHandle sess = TEE_HANDLE_NULL; 154922587dc4SVesa Jääskeläinen TEE_Result res = TEE_ERROR_GENERIC; 155022587dc4SVesa Jääskeläinen uint32_t ret_orig = 0; 155122587dc4SVesa Jääskeläinen 155222587dc4SVesa Jääskeläinen params[0].memref.buffer = seed; 155322587dc4SVesa Jääskeläinen params[0].memref.size = (uint32_t)length; 155422587dc4SVesa Jääskeläinen 155522587dc4SVesa Jääskeläinen res = TEE_OpenTASession(&system_uuid, TEE_TIMEOUT_INFINITE, 0, NULL, 155622587dc4SVesa Jääskeläinen &sess, &ret_orig); 155722587dc4SVesa Jääskeläinen if (res != TEE_SUCCESS) { 155822587dc4SVesa Jääskeläinen EMSG("Can't open session to system PTA"); 155922587dc4SVesa Jääskeläinen return res; 156022587dc4SVesa Jääskeläinen } 156122587dc4SVesa Jääskeläinen 156222587dc4SVesa Jääskeläinen res = TEE_InvokeTACommand(sess, TEE_TIMEOUT_INFINITE, 156322587dc4SVesa Jääskeläinen PTA_SYSTEM_ADD_RNG_ENTROPY, 156422587dc4SVesa Jääskeläinen param_types, params, &ret_orig); 156522587dc4SVesa Jääskeläinen if (res != TEE_SUCCESS) 156622587dc4SVesa Jääskeläinen EMSG("Can't invoke system PTA"); 156722587dc4SVesa Jääskeläinen 156822587dc4SVesa Jääskeläinen TEE_CloseTASession(sess); 156922587dc4SVesa Jääskeläinen return res; 157022587dc4SVesa Jääskeläinen } 157122587dc4SVesa Jääskeläinen 157222587dc4SVesa Jääskeläinen enum pkcs11_rc entry_ck_seed_random(struct pkcs11_client *client, 157322587dc4SVesa Jääskeläinen uint32_t ptypes, TEE_Param *params) 157422587dc4SVesa Jääskeläinen { 157522587dc4SVesa Jääskeläinen const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 157622587dc4SVesa Jääskeläinen TEE_PARAM_TYPE_MEMREF_INPUT, 157722587dc4SVesa Jääskeläinen TEE_PARAM_TYPE_NONE, 157822587dc4SVesa Jääskeläinen TEE_PARAM_TYPE_NONE); 157922587dc4SVesa Jääskeläinen TEE_Param *ctrl = params; 158022587dc4SVesa Jääskeläinen TEE_Param *in = params + 1; 158122587dc4SVesa Jääskeläinen enum pkcs11_rc rc = PKCS11_CKR_OK; 158222587dc4SVesa Jääskeläinen struct serialargs ctrlargs = { }; 158322587dc4SVesa Jääskeläinen struct pkcs11_session *session = NULL; 158422587dc4SVesa Jääskeläinen TEE_Result res = TEE_SUCCESS; 158522587dc4SVesa Jääskeläinen 158622587dc4SVesa Jääskeläinen if (!client || ptypes != exp_pt) 158722587dc4SVesa Jääskeläinen return PKCS11_CKR_ARGUMENTS_BAD; 158822587dc4SVesa Jääskeläinen 158922587dc4SVesa Jääskeläinen serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 159022587dc4SVesa Jääskeläinen 159122587dc4SVesa Jääskeläinen rc = serialargs_get_session_from_handle(&ctrlargs, client, &session); 159222587dc4SVesa Jääskeläinen if (rc) 159322587dc4SVesa Jääskeläinen return rc; 159422587dc4SVesa Jääskeläinen 159522587dc4SVesa Jääskeläinen if (serialargs_remaining_bytes(&ctrlargs)) 159622587dc4SVesa Jääskeläinen return PKCS11_CKR_ARGUMENTS_BAD; 159722587dc4SVesa Jääskeläinen 159822587dc4SVesa Jääskeläinen if (in->memref.size && !in->memref.buffer) 159922587dc4SVesa Jääskeläinen return PKCS11_CKR_ARGUMENTS_BAD; 160022587dc4SVesa Jääskeläinen 160122587dc4SVesa Jääskeläinen if (!in->memref.size) 160222587dc4SVesa Jääskeläinen return PKCS11_CKR_OK; 160322587dc4SVesa Jääskeläinen 160422587dc4SVesa Jääskeläinen res = seed_rng_pool(in->memref.buffer, in->memref.size); 160522587dc4SVesa Jääskeläinen if (res != TEE_SUCCESS) 160622587dc4SVesa Jääskeläinen return PKCS11_CKR_FUNCTION_FAILED; 160722587dc4SVesa Jääskeläinen 160822587dc4SVesa Jääskeläinen DMSG("PKCS11 session %"PRIu32": seed random", session->handle); 160922587dc4SVesa Jääskeläinen 161022587dc4SVesa Jääskeläinen return PKCS11_CKR_OK; 161122587dc4SVesa Jääskeläinen } 161222587dc4SVesa Jääskeläinen 161322587dc4SVesa Jääskeläinen enum pkcs11_rc entry_ck_generate_random(struct pkcs11_client *client, 161422587dc4SVesa Jääskeläinen uint32_t ptypes, TEE_Param *params) 161522587dc4SVesa Jääskeläinen { 161622587dc4SVesa Jääskeläinen const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 161722587dc4SVesa Jääskeläinen TEE_PARAM_TYPE_NONE, 161822587dc4SVesa Jääskeläinen TEE_PARAM_TYPE_MEMREF_OUTPUT, 161922587dc4SVesa Jääskeläinen TEE_PARAM_TYPE_NONE); 162022587dc4SVesa Jääskeläinen TEE_Param *ctrl = params; 162122587dc4SVesa Jääskeläinen TEE_Param *out = params + 2; 162222587dc4SVesa Jääskeläinen enum pkcs11_rc rc = PKCS11_CKR_OK; 162322587dc4SVesa Jääskeläinen struct serialargs ctrlargs = { }; 162422587dc4SVesa Jääskeläinen struct pkcs11_session *session = NULL; 162522587dc4SVesa Jääskeläinen void *buffer = NULL; 162622587dc4SVesa Jääskeläinen size_t buffer_size = 0; 162722587dc4SVesa Jääskeläinen uint8_t *data = NULL; 162822587dc4SVesa Jääskeläinen size_t left = 0; 162922587dc4SVesa Jääskeläinen 163022587dc4SVesa Jääskeläinen if (!client || ptypes != exp_pt) 163122587dc4SVesa Jääskeläinen return PKCS11_CKR_ARGUMENTS_BAD; 163222587dc4SVesa Jääskeläinen 163322587dc4SVesa Jääskeläinen serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 163422587dc4SVesa Jääskeläinen 163522587dc4SVesa Jääskeläinen rc = serialargs_get_session_from_handle(&ctrlargs, client, &session); 163622587dc4SVesa Jääskeläinen if (rc) 163722587dc4SVesa Jääskeläinen return rc; 163822587dc4SVesa Jääskeläinen 163922587dc4SVesa Jääskeläinen if (serialargs_remaining_bytes(&ctrlargs)) 164022587dc4SVesa Jääskeläinen return PKCS11_CKR_ARGUMENTS_BAD; 164122587dc4SVesa Jääskeläinen 164222587dc4SVesa Jääskeläinen if (out->memref.size && !out->memref.buffer) 164322587dc4SVesa Jääskeläinen return PKCS11_CKR_ARGUMENTS_BAD; 164422587dc4SVesa Jääskeläinen 164522587dc4SVesa Jääskeläinen if (!out->memref.size) 164622587dc4SVesa Jääskeläinen return PKCS11_CKR_OK; 164722587dc4SVesa Jääskeläinen 164822587dc4SVesa Jääskeläinen buffer_size = MIN(out->memref.size, RNG_CHUNK_SIZE); 164922587dc4SVesa Jääskeläinen buffer = TEE_Malloc(buffer_size, TEE_MALLOC_FILL_ZERO); 165022587dc4SVesa Jääskeläinen if (!buffer) 165122587dc4SVesa Jääskeläinen return PKCS11_CKR_DEVICE_MEMORY; 165222587dc4SVesa Jääskeläinen 165322587dc4SVesa Jääskeläinen data = out->memref.buffer; 165422587dc4SVesa Jääskeläinen left = out->memref.size; 165522587dc4SVesa Jääskeläinen 165622587dc4SVesa Jääskeläinen while (left) { 165722587dc4SVesa Jääskeläinen size_t count = MIN(left, buffer_size); 165822587dc4SVesa Jääskeläinen 165922587dc4SVesa Jääskeläinen TEE_GenerateRandom(buffer, count); 166022587dc4SVesa Jääskeläinen TEE_MemMove(data, buffer, count); 166122587dc4SVesa Jääskeläinen 166222587dc4SVesa Jääskeläinen data += count; 166322587dc4SVesa Jääskeläinen left -= count; 166422587dc4SVesa Jääskeläinen } 166522587dc4SVesa Jääskeläinen 166622587dc4SVesa Jääskeläinen DMSG("PKCS11 session %"PRIu32": generate random", session->handle); 166722587dc4SVesa Jääskeläinen 166822587dc4SVesa Jääskeläinen TEE_Free(buffer); 166922587dc4SVesa Jääskeläinen 167022587dc4SVesa Jääskeläinen return PKCS11_CKR_OK; 167122587dc4SVesa Jääskeläinen } 1672