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