1c84ccd0aSEtienne Carriere // SPDX-License-Identifier: BSD-2-Clause 2c84ccd0aSEtienne Carriere /* 3c84ccd0aSEtienne Carriere * Copyright (c) 2017-2020, Linaro Limited 4c84ccd0aSEtienne Carriere */ 5c84ccd0aSEtienne Carriere 6c84ccd0aSEtienne Carriere #include <assert.h> 7d38f9635SEtienne Carriere #include <confine_array_index.h> 8c84ccd0aSEtienne Carriere #include <pkcs11_ta.h> 9c84ccd0aSEtienne Carriere #include <string.h> 10c84ccd0aSEtienne Carriere #include <string_ext.h> 11c84ccd0aSEtienne Carriere #include <sys/queue.h> 12c84ccd0aSEtienne Carriere #include <tee_api_types.h> 13c84ccd0aSEtienne Carriere #include <tee_internal_api_extensions.h> 14c84ccd0aSEtienne Carriere #include <util.h> 15c84ccd0aSEtienne Carriere 16c84ccd0aSEtienne Carriere #include "pkcs11_token.h" 17c84ccd0aSEtienne Carriere #include "pkcs11_helpers.h" 1822ac6984SEtienne Carriere #include "serializer.h" 19c84ccd0aSEtienne Carriere 20c84ccd0aSEtienne Carriere /* Provide 3 slots/tokens, ID is token index */ 21c84ccd0aSEtienne Carriere #ifndef CFG_PKCS11_TA_TOKEN_COUNT 22c84ccd0aSEtienne Carriere #define TOKEN_COUNT 3 23c84ccd0aSEtienne Carriere #else 24c84ccd0aSEtienne Carriere #define TOKEN_COUNT CFG_PKCS11_TA_TOKEN_COUNT 25c84ccd0aSEtienne Carriere #endif 26c84ccd0aSEtienne Carriere 27c84ccd0aSEtienne Carriere /* Static allocation of tokens runtime instances (reset to 0 at load) */ 28c84ccd0aSEtienne Carriere struct ck_token ck_token[TOKEN_COUNT]; 29c84ccd0aSEtienne Carriere 30c84ccd0aSEtienne Carriere struct ck_token *get_token(unsigned int token_id) 31c84ccd0aSEtienne Carriere { 32d38f9635SEtienne Carriere if (token_id < TOKEN_COUNT) 33d38f9635SEtienne Carriere return &ck_token[confine_array_index(token_id, TOKEN_COUNT)]; 34c84ccd0aSEtienne Carriere 35d38f9635SEtienne Carriere return NULL; 36c84ccd0aSEtienne Carriere } 37c84ccd0aSEtienne Carriere 38c84ccd0aSEtienne Carriere unsigned int get_token_id(struct ck_token *token) 39c84ccd0aSEtienne Carriere { 40c84ccd0aSEtienne Carriere ptrdiff_t id = token - ck_token; 41c84ccd0aSEtienne Carriere 42c84ccd0aSEtienne Carriere assert(id >= 0 && id < TOKEN_COUNT); 43c84ccd0aSEtienne Carriere return id; 44c84ccd0aSEtienne Carriere } 45c84ccd0aSEtienne Carriere 46c84ccd0aSEtienne Carriere static TEE_Result pkcs11_token_init(unsigned int id) 47c84ccd0aSEtienne Carriere { 48c84ccd0aSEtienne Carriere struct ck_token *token = init_persistent_db(id); 49c84ccd0aSEtienne Carriere 50c84ccd0aSEtienne Carriere if (!token) 51c84ccd0aSEtienne Carriere return TEE_ERROR_SECURITY; 52c84ccd0aSEtienne Carriere 53c84ccd0aSEtienne Carriere if (token->state == PKCS11_TOKEN_RESET) { 54c84ccd0aSEtienne Carriere /* As per PKCS#11 spec, token resets to read/write state */ 55c84ccd0aSEtienne Carriere token->state = PKCS11_TOKEN_READ_WRITE; 56c84ccd0aSEtienne Carriere token->session_count = 0; 57c84ccd0aSEtienne Carriere token->rw_session_count = 0; 58c84ccd0aSEtienne Carriere } 59c84ccd0aSEtienne Carriere 60c84ccd0aSEtienne Carriere return TEE_SUCCESS; 61c84ccd0aSEtienne Carriere } 62c84ccd0aSEtienne Carriere 63c84ccd0aSEtienne Carriere TEE_Result pkcs11_init(void) 64c84ccd0aSEtienne Carriere { 65c84ccd0aSEtienne Carriere unsigned int id = 0; 66c84ccd0aSEtienne Carriere TEE_Result ret = TEE_ERROR_GENERIC; 67c84ccd0aSEtienne Carriere 68c84ccd0aSEtienne Carriere for (id = 0; id < TOKEN_COUNT; id++) { 69c84ccd0aSEtienne Carriere ret = pkcs11_token_init(id); 70c84ccd0aSEtienne Carriere if (ret) 71c84ccd0aSEtienne Carriere return ret; 72c84ccd0aSEtienne Carriere } 73c84ccd0aSEtienne Carriere 74c84ccd0aSEtienne Carriere return ret; 75c84ccd0aSEtienne Carriere } 76c84ccd0aSEtienne Carriere 77c84ccd0aSEtienne Carriere void pkcs11_deinit(void) 78c84ccd0aSEtienne Carriere { 79c84ccd0aSEtienne Carriere unsigned int id = 0; 80c84ccd0aSEtienne Carriere 81c84ccd0aSEtienne Carriere for (id = 0; id < TOKEN_COUNT; id++) 82c84ccd0aSEtienne Carriere close_persistent_db(get_token(id)); 83c84ccd0aSEtienne Carriere } 8422ac6984SEtienne Carriere 8522ac6984SEtienne Carriere uint32_t entry_ck_slot_list(uint32_t ptypes, TEE_Param *params) 8622ac6984SEtienne Carriere { 8722ac6984SEtienne Carriere const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 8822ac6984SEtienne Carriere TEE_PARAM_TYPE_NONE, 8922ac6984SEtienne Carriere TEE_PARAM_TYPE_MEMREF_OUTPUT, 9022ac6984SEtienne Carriere TEE_PARAM_TYPE_NONE); 9122ac6984SEtienne Carriere TEE_Param *out = ¶ms[2]; 9222ac6984SEtienne Carriere uint32_t token_id = 0; 9322ac6984SEtienne Carriere const size_t out_size = sizeof(token_id) * TOKEN_COUNT; 9422ac6984SEtienne Carriere uint8_t *id = NULL; 9522ac6984SEtienne Carriere 9622ac6984SEtienne Carriere if (ptypes != exp_pt || 9722ac6984SEtienne Carriere params[0].memref.size != TEE_PARAM0_SIZE_MIN) 9822ac6984SEtienne Carriere return PKCS11_CKR_ARGUMENTS_BAD; 9922ac6984SEtienne Carriere 10022ac6984SEtienne Carriere if (out->memref.size < out_size) { 10122ac6984SEtienne Carriere out->memref.size = out_size; 10222ac6984SEtienne Carriere 10322ac6984SEtienne Carriere if (out->memref.buffer) 10422ac6984SEtienne Carriere return PKCS11_CKR_BUFFER_TOO_SMALL; 10522ac6984SEtienne Carriere else 10622ac6984SEtienne Carriere return PKCS11_CKR_OK; 10722ac6984SEtienne Carriere } 10822ac6984SEtienne Carriere 10922ac6984SEtienne Carriere for (token_id = 0, id = out->memref.buffer; token_id < TOKEN_COUNT; 11022ac6984SEtienne Carriere token_id++, id += sizeof(token_id)) 11122ac6984SEtienne Carriere TEE_MemMove(id, &token_id, sizeof(token_id)); 11222ac6984SEtienne Carriere 11322ac6984SEtienne Carriere out->memref.size = out_size; 11422ac6984SEtienne Carriere 11522ac6984SEtienne Carriere return PKCS11_CKR_OK; 11622ac6984SEtienne Carriere } 117ce94efefSEtienne Carriere 118b3ac5035SEtienne Carriere static void pad_str(uint8_t *str, size_t size) 119b3ac5035SEtienne Carriere { 120b3ac5035SEtienne Carriere int n = strnlen((char *)str, size); 121b3ac5035SEtienne Carriere 122b3ac5035SEtienne Carriere TEE_MemFill(str + n, ' ', size - n); 123b3ac5035SEtienne Carriere } 124b3ac5035SEtienne Carriere 125ce94efefSEtienne Carriere uint32_t entry_ck_slot_info(uint32_t ptypes, TEE_Param *params) 126ce94efefSEtienne Carriere { 127ce94efefSEtienne Carriere const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 128ce94efefSEtienne Carriere TEE_PARAM_TYPE_NONE, 129ce94efefSEtienne Carriere TEE_PARAM_TYPE_MEMREF_OUTPUT, 130ce94efefSEtienne Carriere TEE_PARAM_TYPE_NONE); 131ce94efefSEtienne Carriere TEE_Param *ctrl = ¶ms[0]; 132ce94efefSEtienne Carriere TEE_Param *out = ¶ms[2]; 133ce94efefSEtienne Carriere uint32_t rv = 0; 134ce94efefSEtienne Carriere struct serialargs ctrlargs = { }; 135ce94efefSEtienne Carriere uint32_t token_id = 0; 136ce94efefSEtienne Carriere struct ck_token *token = NULL; 137ce94efefSEtienne Carriere struct pkcs11_slot_info info = { 138ce94efefSEtienne Carriere .slot_description = PKCS11_SLOT_DESCRIPTION, 139ce94efefSEtienne Carriere .manufacturer_id = PKCS11_SLOT_MANUFACTURER, 140ce94efefSEtienne Carriere .flags = PKCS11_CKFS_TOKEN_PRESENT, 141ce94efefSEtienne Carriere .hardware_version = PKCS11_SLOT_HW_VERSION, 142ce94efefSEtienne Carriere .firmware_version = PKCS11_SLOT_FW_VERSION, 143ce94efefSEtienne Carriere }; 144ce94efefSEtienne Carriere 145ce94efefSEtienne Carriere COMPILE_TIME_ASSERT(sizeof(PKCS11_SLOT_DESCRIPTION) <= 146ce94efefSEtienne Carriere sizeof(info.slot_description)); 147ce94efefSEtienne Carriere COMPILE_TIME_ASSERT(sizeof(PKCS11_SLOT_MANUFACTURER) <= 148ce94efefSEtienne Carriere sizeof(info.manufacturer_id)); 149ce94efefSEtienne Carriere 150ce94efefSEtienne Carriere if (ptypes != exp_pt || out->memref.size != sizeof(info)) 151ce94efefSEtienne Carriere return PKCS11_CKR_ARGUMENTS_BAD; 152ce94efefSEtienne Carriere 153ce94efefSEtienne Carriere serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 154ce94efefSEtienne Carriere 155ce94efefSEtienne Carriere rv = serialargs_get(&ctrlargs, &token_id, sizeof(token_id)); 156ce94efefSEtienne Carriere if (rv) 157ce94efefSEtienne Carriere return rv; 158ce94efefSEtienne Carriere 159ce94efefSEtienne Carriere if (serialargs_remaining_bytes(&ctrlargs)) 160ce94efefSEtienne Carriere return PKCS11_CKR_ARGUMENTS_BAD; 161ce94efefSEtienne Carriere 162ce94efefSEtienne Carriere token = get_token(token_id); 163ce94efefSEtienne Carriere if (!token) 164ce94efefSEtienne Carriere return PKCS11_CKR_SLOT_ID_INVALID; 165ce94efefSEtienne Carriere 166b3ac5035SEtienne Carriere pad_str(info.slot_description, sizeof(info.slot_description)); 167b3ac5035SEtienne Carriere pad_str(info.manufacturer_id, sizeof(info.manufacturer_id)); 168ce94efefSEtienne Carriere 169ce94efefSEtienne Carriere out->memref.size = sizeof(info); 170ce94efefSEtienne Carriere TEE_MemMove(out->memref.buffer, &info, out->memref.size); 171ce94efefSEtienne Carriere 172ce94efefSEtienne Carriere return PKCS11_CKR_OK; 173ce94efefSEtienne Carriere } 174030e7392SEtienne Carriere 175030e7392SEtienne Carriere uint32_t entry_ck_token_info(uint32_t ptypes, TEE_Param *params) 176030e7392SEtienne Carriere { 177030e7392SEtienne Carriere const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 178030e7392SEtienne Carriere TEE_PARAM_TYPE_NONE, 179030e7392SEtienne Carriere TEE_PARAM_TYPE_MEMREF_OUTPUT, 180030e7392SEtienne Carriere TEE_PARAM_TYPE_NONE); 181030e7392SEtienne Carriere TEE_Param *ctrl = ¶ms[0]; 182030e7392SEtienne Carriere TEE_Param *out = ¶ms[2]; 183030e7392SEtienne Carriere uint32_t rv = 0; 184030e7392SEtienne Carriere struct serialargs ctrlargs = { }; 185030e7392SEtienne Carriere uint32_t token_id = 0; 186030e7392SEtienne Carriere struct ck_token *token = NULL; 187030e7392SEtienne Carriere struct pkcs11_token_info info = { 188030e7392SEtienne Carriere .manufacturer_id = PKCS11_TOKEN_MANUFACTURER, 189030e7392SEtienne Carriere .model = PKCS11_TOKEN_MODEL, 190030e7392SEtienne Carriere .serial_number = PKCS11_TOKEN_SERIAL_NUMBER, 191030e7392SEtienne Carriere .max_session_count = UINT32_MAX, 192030e7392SEtienne Carriere .max_rw_session_count = UINT32_MAX, 193030e7392SEtienne Carriere .max_pin_len = PKCS11_TOKEN_PIN_SIZE_MAX, 194030e7392SEtienne Carriere .min_pin_len = PKCS11_TOKEN_PIN_SIZE_MIN, 195030e7392SEtienne Carriere .total_public_memory = UINT32_MAX, 196030e7392SEtienne Carriere .free_public_memory = UINT32_MAX, 197030e7392SEtienne Carriere .total_private_memory = UINT32_MAX, 198030e7392SEtienne Carriere .free_private_memory = UINT32_MAX, 199030e7392SEtienne Carriere .hardware_version = PKCS11_TOKEN_HW_VERSION, 200030e7392SEtienne Carriere .firmware_version = PKCS11_TOKEN_FW_VERSION, 201030e7392SEtienne Carriere }; 202030e7392SEtienne Carriere 203030e7392SEtienne Carriere if (ptypes != exp_pt || out->memref.size != sizeof(info)) 204030e7392SEtienne Carriere return PKCS11_CKR_ARGUMENTS_BAD; 205030e7392SEtienne Carriere 206030e7392SEtienne Carriere serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 207030e7392SEtienne Carriere 208030e7392SEtienne Carriere rv = serialargs_get(&ctrlargs, &token_id, sizeof(token_id)); 209030e7392SEtienne Carriere if (rv) 210030e7392SEtienne Carriere return rv; 211030e7392SEtienne Carriere 212030e7392SEtienne Carriere if (serialargs_remaining_bytes(&ctrlargs)) 213030e7392SEtienne Carriere return PKCS11_CKR_ARGUMENTS_BAD; 214030e7392SEtienne Carriere 215030e7392SEtienne Carriere token = get_token(token_id); 216030e7392SEtienne Carriere if (!token) 217030e7392SEtienne Carriere return PKCS11_CKR_SLOT_ID_INVALID; 218030e7392SEtienne Carriere 219030e7392SEtienne Carriere pad_str(info.manufacturer_id, sizeof(info.manufacturer_id)); 220030e7392SEtienne Carriere pad_str(info.model, sizeof(info.model)); 221030e7392SEtienne Carriere pad_str(info.serial_number, sizeof(info.serial_number)); 222030e7392SEtienne Carriere 223030e7392SEtienne Carriere TEE_MemMove(info.label, token->db_main->label, sizeof(info.label)); 224030e7392SEtienne Carriere 225030e7392SEtienne Carriere info.flags = token->db_main->flags; 226030e7392SEtienne Carriere info.session_count = token->session_count; 227030e7392SEtienne Carriere info.rw_session_count = token->rw_session_count; 228030e7392SEtienne Carriere 229030e7392SEtienne Carriere TEE_MemMove(out->memref.buffer, &info, sizeof(info)); 230030e7392SEtienne Carriere 231030e7392SEtienne Carriere return PKCS11_CKR_OK; 232030e7392SEtienne Carriere } 233*6f74919dSEtienne Carriere 234*6f74919dSEtienne Carriere static void dmsg_print_supported_mechanism(unsigned int token_id __maybe_unused, 235*6f74919dSEtienne Carriere uint32_t *array __maybe_unused, 236*6f74919dSEtienne Carriere size_t count __maybe_unused) 237*6f74919dSEtienne Carriere { 238*6f74919dSEtienne Carriere size_t __maybe_unused n = 0; 239*6f74919dSEtienne Carriere 240*6f74919dSEtienne Carriere if (TRACE_LEVEL < TRACE_DEBUG) 241*6f74919dSEtienne Carriere return; 242*6f74919dSEtienne Carriere 243*6f74919dSEtienne Carriere for (n = 0; n < count; n++) 244*6f74919dSEtienne Carriere DMSG("PKCS11 token %"PRIu32": mechanism 0x%04"PRIx32": %s", 245*6f74919dSEtienne Carriere token_id, array[n], id2str_mechanism(array[n])); 246*6f74919dSEtienne Carriere } 247*6f74919dSEtienne Carriere 248*6f74919dSEtienne Carriere uint32_t entry_ck_token_mecha_ids(uint32_t ptypes, TEE_Param *params) 249*6f74919dSEtienne Carriere { 250*6f74919dSEtienne Carriere const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 251*6f74919dSEtienne Carriere TEE_PARAM_TYPE_NONE, 252*6f74919dSEtienne Carriere TEE_PARAM_TYPE_MEMREF_OUTPUT, 253*6f74919dSEtienne Carriere TEE_PARAM_TYPE_NONE); 254*6f74919dSEtienne Carriere TEE_Param *ctrl = ¶ms[0]; 255*6f74919dSEtienne Carriere TEE_Param *out = ¶ms[2]; 256*6f74919dSEtienne Carriere uint32_t rv = 0; 257*6f74919dSEtienne Carriere struct serialargs ctrlargs = { }; 258*6f74919dSEtienne Carriere uint32_t token_id = 0; 259*6f74919dSEtienne Carriere struct ck_token __maybe_unused *token = NULL; 260*6f74919dSEtienne Carriere size_t count = 0; 261*6f74919dSEtienne Carriere uint32_t *array = NULL; 262*6f74919dSEtienne Carriere 263*6f74919dSEtienne Carriere if (ptypes != exp_pt) 264*6f74919dSEtienne Carriere return PKCS11_CKR_ARGUMENTS_BAD; 265*6f74919dSEtienne Carriere 266*6f74919dSEtienne Carriere serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 267*6f74919dSEtienne Carriere 268*6f74919dSEtienne Carriere rv = serialargs_get(&ctrlargs, &token_id, sizeof(token_id)); 269*6f74919dSEtienne Carriere if (rv) 270*6f74919dSEtienne Carriere return rv; 271*6f74919dSEtienne Carriere 272*6f74919dSEtienne Carriere if (serialargs_remaining_bytes(&ctrlargs)) 273*6f74919dSEtienne Carriere return PKCS11_CKR_ARGUMENTS_BAD; 274*6f74919dSEtienne Carriere 275*6f74919dSEtienne Carriere token = get_token(token_id); 276*6f74919dSEtienne Carriere if (!token) 277*6f74919dSEtienne Carriere return PKCS11_CKR_SLOT_ID_INVALID; 278*6f74919dSEtienne Carriere 279*6f74919dSEtienne Carriere count = out->memref.size / sizeof(*array); 280*6f74919dSEtienne Carriere array = tee_malloc_mechanism_list(&count); 281*6f74919dSEtienne Carriere 282*6f74919dSEtienne Carriere if (out->memref.size < count * sizeof(*array)) { 283*6f74919dSEtienne Carriere assert(!array); 284*6f74919dSEtienne Carriere out->memref.size = count * sizeof(*array); 285*6f74919dSEtienne Carriere return PKCS11_CKR_BUFFER_TOO_SMALL; 286*6f74919dSEtienne Carriere } 287*6f74919dSEtienne Carriere 288*6f74919dSEtienne Carriere if (!array) 289*6f74919dSEtienne Carriere return PKCS11_CKR_DEVICE_MEMORY; 290*6f74919dSEtienne Carriere 291*6f74919dSEtienne Carriere dmsg_print_supported_mechanism(token_id, array, count); 292*6f74919dSEtienne Carriere 293*6f74919dSEtienne Carriere out->memref.size = count * sizeof(*array); 294*6f74919dSEtienne Carriere TEE_MemMove(out->memref.buffer, array, out->memref.size); 295*6f74919dSEtienne Carriere 296*6f74919dSEtienne Carriere TEE_Free(array); 297*6f74919dSEtienne Carriere 298*6f74919dSEtienne Carriere return rv; 299*6f74919dSEtienne Carriere } 300