1c84ccd0aSEtienne Carriere // SPDX-License-Identifier: BSD-2-Clause 2c84ccd0aSEtienne Carriere /* 3c84ccd0aSEtienne Carriere * Copyright (c) 2018-2020, Linaro Limited 4c84ccd0aSEtienne Carriere */ 5c84ccd0aSEtienne Carriere 6c84ccd0aSEtienne Carriere #include <assert.h> 7c84ccd0aSEtienne Carriere #include <pkcs11_ta.h> 8c84ccd0aSEtienne Carriere #include <string.h> 9c84ccd0aSEtienne Carriere #include <string_ext.h> 10c84ccd0aSEtienne Carriere #include <tee_internal_api_extensions.h> 11c84ccd0aSEtienne Carriere #include <util.h> 12c84ccd0aSEtienne Carriere 13402d884aSRuchika Gupta #include "attributes.h" 14c84ccd0aSEtienne Carriere #include "pkcs11_token.h" 15c84ccd0aSEtienne Carriere #include "pkcs11_helpers.h" 16c84ccd0aSEtienne Carriere 1760659a86SEtienne Carriere #define PERSISTENT_OBJECT_ID_LEN 32 1860659a86SEtienne Carriere 1960659a86SEtienne Carriere /* 2060659a86SEtienne Carriere * Token persistent objects 21334316feSJens Wiklander * 22334316feSJens Wiklander * The persistent objects are each identified by a UUID. 23334316feSJens Wiklander * The persistent object database stores the list of the UUIDs registered. For 24334316feSJens Wiklander * each it is expected that a file of ID "UUID" is stored in the TA secure 25334316feSJens Wiklander * storage. 2660659a86SEtienne Carriere */ 2760659a86SEtienne Carriere static TEE_Result get_db_file_name(struct ck_token *token, 2860659a86SEtienne Carriere char *name, size_t size) 29c84ccd0aSEtienne Carriere { 3060659a86SEtienne Carriere int n = snprintf(name, size, "token.db.%u", get_token_id(token)); 3160659a86SEtienne Carriere 3260659a86SEtienne Carriere if (n < 0 || (size_t)n >= size) 3360659a86SEtienne Carriere return TEE_ERROR_SECURITY; 3460659a86SEtienne Carriere else 3560659a86SEtienne Carriere return TEE_SUCCESS; 3660659a86SEtienne Carriere } 3760659a86SEtienne Carriere 3860659a86SEtienne Carriere static TEE_Result open_db_file(struct ck_token *token, 3960659a86SEtienne Carriere TEE_ObjectHandle *out_hdl) 4060659a86SEtienne Carriere { 4160659a86SEtienne Carriere char file[PERSISTENT_OBJECT_ID_LEN] = { }; 4260659a86SEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 4360659a86SEtienne Carriere 4460659a86SEtienne Carriere res = get_db_file_name(token, file, sizeof(file)); 4560659a86SEtienne Carriere if (res) 4660659a86SEtienne Carriere return res; 4760659a86SEtienne Carriere 4860659a86SEtienne Carriere return TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE, file, sizeof(file), 4960659a86SEtienne Carriere TEE_DATA_FLAG_ACCESS_READ | 5060659a86SEtienne Carriere TEE_DATA_FLAG_ACCESS_WRITE, 5160659a86SEtienne Carriere out_hdl); 5260659a86SEtienne Carriere } 5360659a86SEtienne Carriere 54e86828f4SJens Wiklander void update_persistent_db(struct ck_token *token) 55e86828f4SJens Wiklander { 56e86828f4SJens Wiklander TEE_Result res = TEE_ERROR_GENERIC; 57e86828f4SJens Wiklander TEE_ObjectHandle db_hdl = TEE_HANDLE_NULL; 58e86828f4SJens Wiklander 59e86828f4SJens Wiklander res = open_db_file(token, &db_hdl); 60e86828f4SJens Wiklander if (res) { 61e86828f4SJens Wiklander EMSG("Failed to open token persistent db: %#"PRIx32, res); 62e86828f4SJens Wiklander TEE_Panic(0); 63e86828f4SJens Wiklander } 64e86828f4SJens Wiklander res = TEE_WriteObjectData(db_hdl, token->db_main, 65e86828f4SJens Wiklander sizeof(*token->db_main)); 66e86828f4SJens Wiklander if (res) { 67e86828f4SJens Wiklander EMSG("Failed to write to token persistent db: %#"PRIx32, res); 68e86828f4SJens Wiklander TEE_Panic(0); 69e86828f4SJens Wiklander } 70e86828f4SJens Wiklander 71e86828f4SJens Wiklander TEE_CloseObject(db_hdl); 72e86828f4SJens Wiklander } 73e86828f4SJens Wiklander 74bef8bc68SJens Wiklander static enum pkcs11_rc do_hash(uint32_t user, const uint8_t *pin, 75bef8bc68SJens Wiklander size_t pin_size, uint32_t salt, 76bef8bc68SJens Wiklander uint8_t hash[TEE_MAX_HASH_SIZE]) 77bef8bc68SJens Wiklander { 78bef8bc68SJens Wiklander TEE_Result res = TEE_SUCCESS; 79bef8bc68SJens Wiklander TEE_OperationHandle oh = TEE_HANDLE_NULL; 80*c7f1b4f7SJens Wiklander size_t sz = TEE_MAX_HASH_SIZE; 81bef8bc68SJens Wiklander 82bef8bc68SJens Wiklander res = TEE_AllocateOperation(&oh, TEE_ALG_SHA256, TEE_MODE_DIGEST, 0); 83bef8bc68SJens Wiklander if (res) 84bef8bc68SJens Wiklander return tee2pkcs_error(res); 85bef8bc68SJens Wiklander 86bef8bc68SJens Wiklander TEE_DigestUpdate(oh, &user, sizeof(user)); 87bef8bc68SJens Wiklander TEE_DigestUpdate(oh, &salt, sizeof(salt)); 88bef8bc68SJens Wiklander res = TEE_DigestDoFinal(oh, pin, pin_size, hash, &sz); 89bef8bc68SJens Wiklander TEE_FreeOperation(oh); 90bef8bc68SJens Wiklander 91bef8bc68SJens Wiklander if (res) 92bef8bc68SJens Wiklander return PKCS11_CKR_GENERAL_ERROR; 93bef8bc68SJens Wiklander 94bef8bc68SJens Wiklander memset(hash + sz, 0, TEE_MAX_HASH_SIZE - sz); 95bef8bc68SJens Wiklander return PKCS11_CKR_OK; 96bef8bc68SJens Wiklander } 97bef8bc68SJens Wiklander 98bef8bc68SJens Wiklander enum pkcs11_rc hash_pin(enum pkcs11_user_type user, const uint8_t *pin, 99bef8bc68SJens Wiklander size_t pin_size, uint32_t *salt, 100bef8bc68SJens Wiklander uint8_t hash[TEE_MAX_HASH_SIZE]) 101bef8bc68SJens Wiklander { 102bef8bc68SJens Wiklander enum pkcs11_rc rc = PKCS11_CKR_OK; 103bef8bc68SJens Wiklander uint32_t s = 0; 104bef8bc68SJens Wiklander 105bef8bc68SJens Wiklander TEE_GenerateRandom(&s, sizeof(s)); 106bef8bc68SJens Wiklander if (!s) 107bef8bc68SJens Wiklander s++; 108bef8bc68SJens Wiklander 109bef8bc68SJens Wiklander rc = do_hash(user, pin, pin_size, s, hash); 110bef8bc68SJens Wiklander if (!rc) 111bef8bc68SJens Wiklander *salt = s; 112bef8bc68SJens Wiklander return rc; 113bef8bc68SJens Wiklander } 114bef8bc68SJens Wiklander 115bef8bc68SJens Wiklander enum pkcs11_rc verify_pin(enum pkcs11_user_type user, const uint8_t *pin, 116bef8bc68SJens Wiklander size_t pin_size, uint32_t salt, 117bef8bc68SJens Wiklander const uint8_t hash[TEE_MAX_HASH_SIZE]) 118bef8bc68SJens Wiklander { 119bef8bc68SJens Wiklander uint8_t tmp_hash[TEE_MAX_HASH_SIZE] = { 0 }; 120bef8bc68SJens Wiklander enum pkcs11_rc rc = PKCS11_CKR_OK; 121bef8bc68SJens Wiklander 122bef8bc68SJens Wiklander rc = do_hash(user, pin, pin_size, salt, tmp_hash); 123bef8bc68SJens Wiklander if (rc) 124bef8bc68SJens Wiklander return rc; 125bef8bc68SJens Wiklander 126bef8bc68SJens Wiklander if (buf_compare_ct(tmp_hash, hash, TEE_MAX_HASH_SIZE)) 127bef8bc68SJens Wiklander rc = PKCS11_CKR_PIN_INCORRECT; 128bef8bc68SJens Wiklander 129bef8bc68SJens Wiklander return rc; 130bef8bc68SJens Wiklander } 131bef8bc68SJens Wiklander 1321a27b197SVesa Jääskeläinen #if defined(CFG_PKCS11_TA_AUTH_TEE_IDENTITY) 1331a27b197SVesa Jääskeläinen enum pkcs11_rc setup_so_identity_auth_from_client(struct ck_token *token) 1341a27b197SVesa Jääskeläinen { 1351a27b197SVesa Jääskeläinen TEE_Identity identity = { }; 1361a27b197SVesa Jääskeläinen TEE_Result res = TEE_SUCCESS; 1371a27b197SVesa Jääskeläinen 1381a27b197SVesa Jääskeläinen res = TEE_GetPropertyAsIdentity(TEE_PROPSET_CURRENT_CLIENT, 1391a27b197SVesa Jääskeläinen "gpd.client.identity", &identity); 1401a27b197SVesa Jääskeläinen if (res != TEE_SUCCESS) { 1411a27b197SVesa Jääskeläinen EMSG("TEE_GetPropertyAsIdentity: returned %#"PRIx32, res); 1421a27b197SVesa Jääskeläinen return PKCS11_CKR_PIN_INVALID; 1431a27b197SVesa Jääskeläinen } 1441a27b197SVesa Jääskeläinen 1451a27b197SVesa Jääskeläinen TEE_MemMove(&token->db_main->so_identity, &identity, sizeof(identity)); 1461a27b197SVesa Jääskeläinen token->db_main->flags |= PKCS11_CKFT_PROTECTED_AUTHENTICATION_PATH; 1471a27b197SVesa Jääskeläinen 1481a27b197SVesa Jääskeläinen token->db_main->so_pin_salt = 0; 1491a27b197SVesa Jääskeläinen 1501a27b197SVesa Jääskeläinen return PKCS11_CKR_OK; 1511a27b197SVesa Jääskeläinen } 1521a27b197SVesa Jääskeläinen 1531a27b197SVesa Jääskeläinen enum pkcs11_rc setup_identity_auth_from_pin(struct ck_token *token, 1541a27b197SVesa Jääskeläinen enum pkcs11_user_type user_type, 1551a27b197SVesa Jääskeläinen const uint8_t *pin, 1561a27b197SVesa Jääskeläinen size_t pin_size) 1571a27b197SVesa Jääskeläinen { 1581a27b197SVesa Jääskeläinen TEE_Identity identity = { }; 1591a27b197SVesa Jääskeläinen TEE_Result res = TEE_SUCCESS; 1601a27b197SVesa Jääskeläinen uint32_t flags_clear = 0; 1611a27b197SVesa Jääskeläinen uint32_t flags_set = 0; 1621a27b197SVesa Jääskeläinen char *acl_string = NULL; 1631a27b197SVesa Jääskeläinen char *uuid_str = NULL; 1641a27b197SVesa Jääskeläinen 1651a27b197SVesa Jääskeläinen assert(token->db_main->flags & 1661a27b197SVesa Jääskeläinen PKCS11_CKFT_PROTECTED_AUTHENTICATION_PATH); 1671a27b197SVesa Jääskeläinen 1681a27b197SVesa Jääskeläinen if (!pin) { 1691a27b197SVesa Jääskeläinen /* Use client identity */ 1701a27b197SVesa Jääskeläinen res = TEE_GetPropertyAsIdentity(TEE_PROPSET_CURRENT_CLIENT, 1711a27b197SVesa Jääskeläinen "gpd.client.identity", 1721a27b197SVesa Jääskeläinen &identity); 1731a27b197SVesa Jääskeläinen if (res != TEE_SUCCESS) { 1741a27b197SVesa Jääskeläinen EMSG("TEE_GetPropertyAsIdentity: returned %#"PRIx32, 1751a27b197SVesa Jääskeläinen res); 1761a27b197SVesa Jääskeläinen return PKCS11_CKR_PIN_INVALID; 1771a27b197SVesa Jääskeläinen } 1781a27b197SVesa Jääskeläinen } else { 1791a27b197SVesa Jääskeläinen /* Parse PIN ACL string: <login type>:<client id> */ 1801a27b197SVesa Jääskeläinen acl_string = TEE_Malloc(pin_size + 1, TEE_MALLOC_FILL_ZERO); 1811a27b197SVesa Jääskeläinen if (!acl_string) 1821a27b197SVesa Jääskeläinen return PKCS11_CKR_DEVICE_MEMORY; 1831a27b197SVesa Jääskeläinen TEE_MemMove(acl_string, pin, pin_size); 1841a27b197SVesa Jääskeläinen 1851a27b197SVesa Jääskeläinen uuid_str = strstr(acl_string, ":"); 1861a27b197SVesa Jääskeläinen if (uuid_str) 1871a27b197SVesa Jääskeläinen uuid_str++; 1881a27b197SVesa Jääskeläinen if (strcmp(PKCS11_AUTH_TEE_IDENTITY_PUBLIC, acl_string) == 0) { 1891a27b197SVesa Jääskeläinen identity.login = TEE_LOGIN_PUBLIC; 1901a27b197SVesa Jääskeläinen } else if (strstr(acl_string, PKCS11_AUTH_TEE_IDENTITY_USER) == 1911a27b197SVesa Jääskeläinen acl_string) { 1921a27b197SVesa Jääskeläinen identity.login = TEE_LOGIN_USER; 1931a27b197SVesa Jääskeläinen } else if (strstr(acl_string, PKCS11_AUTH_TEE_IDENTITY_GROUP) == 1941a27b197SVesa Jääskeläinen acl_string) { 1951a27b197SVesa Jääskeläinen identity.login = TEE_LOGIN_GROUP; 1961a27b197SVesa Jääskeläinen } else { 1971a27b197SVesa Jääskeläinen EMSG("Invalid PIN ACL string - login"); 1981a27b197SVesa Jääskeläinen TEE_Free(acl_string); 1991a27b197SVesa Jääskeläinen return PKCS11_CKR_PIN_INVALID; 2001a27b197SVesa Jääskeläinen } 2011a27b197SVesa Jääskeläinen 2021a27b197SVesa Jääskeläinen if (identity.login != TEE_LOGIN_PUBLIC) { 2031a27b197SVesa Jääskeläinen if (!uuid_str) { 2041a27b197SVesa Jääskeläinen EMSG("Invalid PIN ACL string - colon"); 2051a27b197SVesa Jääskeläinen TEE_Free(acl_string); 2061a27b197SVesa Jääskeläinen return PKCS11_CKR_PIN_INVALID; 2071a27b197SVesa Jääskeläinen } 2081a27b197SVesa Jääskeläinen 2091a27b197SVesa Jääskeläinen res = tee_uuid_from_str(&identity.uuid, uuid_str); 2101a27b197SVesa Jääskeläinen if (res) { 2111a27b197SVesa Jääskeläinen EMSG("Invalid PIN ACL string - client id"); 2121a27b197SVesa Jääskeläinen TEE_Free(acl_string); 2131a27b197SVesa Jääskeläinen return PKCS11_CKR_PIN_INVALID; 2141a27b197SVesa Jääskeläinen } 2151a27b197SVesa Jääskeläinen } 2161a27b197SVesa Jääskeläinen 2171a27b197SVesa Jääskeläinen TEE_Free(acl_string); 2181a27b197SVesa Jääskeläinen } 2191a27b197SVesa Jääskeläinen 2201a27b197SVesa Jääskeläinen switch (user_type) { 2211a27b197SVesa Jääskeläinen case PKCS11_CKU_SO: 2221a27b197SVesa Jääskeläinen token->db_main->so_pin_count = 0; 2231a27b197SVesa Jääskeläinen token->db_main->so_pin_salt = 0; 2241a27b197SVesa Jääskeläinen flags_clear = PKCS11_CKFT_SO_PIN_COUNT_LOW | 2251a27b197SVesa Jääskeläinen PKCS11_CKFT_SO_PIN_FINAL_TRY | 2261a27b197SVesa Jääskeläinen PKCS11_CKFT_SO_PIN_LOCKED | 2271a27b197SVesa Jääskeläinen PKCS11_CKFT_SO_PIN_TO_BE_CHANGED; 2281a27b197SVesa Jääskeläinen 2291a27b197SVesa Jääskeläinen TEE_MemMove(&token->db_main->so_identity, &identity, 2301a27b197SVesa Jääskeläinen sizeof(identity)); 2311a27b197SVesa Jääskeläinen break; 2321a27b197SVesa Jääskeläinen case PKCS11_CKU_USER: 2331a27b197SVesa Jääskeläinen token->db_main->user_pin_count = 0; 2341a27b197SVesa Jääskeläinen token->db_main->user_pin_salt = 0; 2351a27b197SVesa Jääskeläinen flags_clear = PKCS11_CKFT_USER_PIN_COUNT_LOW | 2361a27b197SVesa Jääskeläinen PKCS11_CKFT_USER_PIN_FINAL_TRY | 2371a27b197SVesa Jääskeläinen PKCS11_CKFT_USER_PIN_LOCKED | 2381a27b197SVesa Jääskeläinen PKCS11_CKFT_USER_PIN_TO_BE_CHANGED; 2391a27b197SVesa Jääskeläinen flags_set = PKCS11_CKFT_USER_PIN_INITIALIZED; 2401a27b197SVesa Jääskeläinen 2411a27b197SVesa Jääskeläinen TEE_MemMove(&token->db_main->user_identity, &identity, 2421a27b197SVesa Jääskeläinen sizeof(identity)); 2431a27b197SVesa Jääskeläinen break; 2441a27b197SVesa Jääskeläinen default: 2451a27b197SVesa Jääskeläinen return PKCS11_CKR_FUNCTION_FAILED; 2461a27b197SVesa Jääskeläinen } 2471a27b197SVesa Jääskeläinen 2481a27b197SVesa Jääskeläinen token->db_main->flags &= ~flags_clear; 2491a27b197SVesa Jääskeläinen token->db_main->flags |= flags_set; 2501a27b197SVesa Jääskeläinen 2511a27b197SVesa Jääskeläinen return PKCS11_CKR_OK; 2521a27b197SVesa Jääskeläinen } 2531a27b197SVesa Jääskeläinen 2541a27b197SVesa Jääskeläinen enum pkcs11_rc verify_identity_auth(struct ck_token *token, 2551a27b197SVesa Jääskeläinen enum pkcs11_user_type user_type) 2561a27b197SVesa Jääskeläinen { 2571a27b197SVesa Jääskeläinen TEE_Identity identity = { }; 2581a27b197SVesa Jääskeläinen TEE_Result res = TEE_SUCCESS; 2591a27b197SVesa Jääskeläinen 2601a27b197SVesa Jääskeläinen assert(token->db_main->flags & 2611a27b197SVesa Jääskeläinen PKCS11_CKFT_PROTECTED_AUTHENTICATION_PATH); 2621a27b197SVesa Jääskeläinen 2631a27b197SVesa Jääskeläinen res = TEE_GetPropertyAsIdentity(TEE_PROPSET_CURRENT_CLIENT, 2641a27b197SVesa Jääskeläinen "gpd.client.identity", &identity); 2651a27b197SVesa Jääskeläinen if (res != TEE_SUCCESS) { 2661a27b197SVesa Jääskeläinen EMSG("TEE_GetPropertyAsIdentity: returned %#"PRIx32, res); 2671a27b197SVesa Jääskeläinen return PKCS11_CKR_PIN_INVALID; 2681a27b197SVesa Jääskeläinen } 2691a27b197SVesa Jääskeläinen 2701a27b197SVesa Jääskeläinen if (user_type == PKCS11_CKU_SO) { 2711a27b197SVesa Jääskeläinen if (TEE_MemCompare(&token->db_main->so_identity, &identity, 2721a27b197SVesa Jääskeläinen sizeof(identity))) 2731a27b197SVesa Jääskeläinen return PKCS11_CKR_PIN_INCORRECT; 2741a27b197SVesa Jääskeläinen } else if (user_type == PKCS11_CKU_USER) { 2751a27b197SVesa Jääskeläinen if (TEE_MemCompare(&token->db_main->user_identity, &identity, 2761a27b197SVesa Jääskeläinen sizeof(identity))) 2771a27b197SVesa Jääskeläinen return PKCS11_CKR_PIN_INCORRECT; 2781a27b197SVesa Jääskeläinen } else { 2791a27b197SVesa Jääskeläinen return PKCS11_CKR_PIN_INCORRECT; 2801a27b197SVesa Jääskeläinen } 2811a27b197SVesa Jääskeläinen 2821a27b197SVesa Jääskeläinen return PKCS11_CKR_OK; 2831a27b197SVesa Jääskeläinen } 2841a27b197SVesa Jääskeläinen #endif /* CFG_PKCS11_TA_AUTH_TEE_IDENTITY */ 2851a27b197SVesa Jääskeläinen 286c84ccd0aSEtienne Carriere /* 28760659a86SEtienne Carriere * Release resources relate to persistent database 28860659a86SEtienne Carriere */ 28960659a86SEtienne Carriere void close_persistent_db(struct ck_token *token __unused) 29060659a86SEtienne Carriere { 29160659a86SEtienne Carriere } 29260659a86SEtienne Carriere 293334316feSJens Wiklander static int get_persistent_obj_idx(struct ck_token *token, TEE_UUID *uuid) 294334316feSJens Wiklander { 295334316feSJens Wiklander size_t i = 0; 296334316feSJens Wiklander 297334316feSJens Wiklander if (!uuid) 298334316feSJens Wiklander return -1; 299334316feSJens Wiklander 300334316feSJens Wiklander for (i = 0; i < token->db_objs->count; i++) 301334316feSJens Wiklander if (!TEE_MemCompare(token->db_objs->uuids + i, 302334316feSJens Wiklander uuid, sizeof(TEE_UUID))) 303334316feSJens Wiklander return i; 304334316feSJens Wiklander 305334316feSJens Wiklander return -1; 306334316feSJens Wiklander } 307334316feSJens Wiklander 308334316feSJens Wiklander /* UUID for persistent object */ 309334316feSJens Wiklander enum pkcs11_rc create_object_uuid(struct ck_token *token, 310334316feSJens Wiklander struct pkcs11_object *obj) 311334316feSJens Wiklander { 312334316feSJens Wiklander assert(!obj->uuid); 313334316feSJens Wiklander 314334316feSJens Wiklander obj->uuid = TEE_Malloc(sizeof(TEE_UUID), 315334316feSJens Wiklander TEE_USER_MEM_HINT_NO_FILL_ZERO); 316334316feSJens Wiklander if (!obj->uuid) 317334316feSJens Wiklander return PKCS11_CKR_DEVICE_MEMORY; 318334316feSJens Wiklander 319bc555ee0SVesa Jääskeläinen obj->token = token; 320bc555ee0SVesa Jääskeläinen 321334316feSJens Wiklander do { 322334316feSJens Wiklander TEE_GenerateRandom(obj->uuid, sizeof(TEE_UUID)); 323334316feSJens Wiklander } while (get_persistent_obj_idx(token, obj->uuid) >= 0); 324334316feSJens Wiklander 325334316feSJens Wiklander return PKCS11_CKR_OK; 326334316feSJens Wiklander } 327334316feSJens Wiklander 328334316feSJens Wiklander void destroy_object_uuid(struct ck_token *token __maybe_unused, 329334316feSJens Wiklander struct pkcs11_object *obj) 330334316feSJens Wiklander { 331334316feSJens Wiklander assert(get_persistent_obj_idx(token, obj->uuid) < 0); 332334316feSJens Wiklander 333334316feSJens Wiklander TEE_Free(obj->uuid); 334334316feSJens Wiklander obj->uuid = NULL; 335334316feSJens Wiklander } 336334316feSJens Wiklander 337334316feSJens Wiklander enum pkcs11_rc get_persistent_objects_list(struct ck_token *token, 338334316feSJens Wiklander TEE_UUID *array, size_t *size) 339334316feSJens Wiklander { 340334316feSJens Wiklander size_t out_size = *size; 341334316feSJens Wiklander 342334316feSJens Wiklander *size = token->db_objs->count * sizeof(TEE_UUID); 343334316feSJens Wiklander 344334316feSJens Wiklander if (out_size < *size) 345334316feSJens Wiklander return PKCS11_CKR_BUFFER_TOO_SMALL; 346334316feSJens Wiklander 347334316feSJens Wiklander if (array) 348334316feSJens Wiklander TEE_MemMove(array, token->db_objs->uuids, *size); 349334316feSJens Wiklander 350334316feSJens Wiklander return PKCS11_CKR_OK; 351334316feSJens Wiklander } 352334316feSJens Wiklander 353334316feSJens Wiklander enum pkcs11_rc unregister_persistent_object(struct ck_token *token, 354334316feSJens Wiklander TEE_UUID *uuid) 355334316feSJens Wiklander { 356334316feSJens Wiklander TEE_ObjectHandle db_hdl = TEE_HANDLE_NULL; 357334316feSJens Wiklander struct token_persistent_objs *ptr = NULL; 358334316feSJens Wiklander TEE_Result res = TEE_ERROR_GENERIC; 359334316feSJens Wiklander int count = 0; 360334316feSJens Wiklander int idx = 0; 361334316feSJens Wiklander 362334316feSJens Wiklander if (!uuid) 363334316feSJens Wiklander return PKCS11_CKR_OK; 364334316feSJens Wiklander 365334316feSJens Wiklander idx = get_persistent_obj_idx(token, uuid); 366334316feSJens Wiklander if (idx < 0) { 367334316feSJens Wiklander DMSG("Cannot unregister an invalid persistent object"); 368334316feSJens Wiklander return PKCS11_RV_NOT_FOUND; 369334316feSJens Wiklander } 370334316feSJens Wiklander 371334316feSJens Wiklander ptr = TEE_Malloc(sizeof(struct token_persistent_objs) + 372334316feSJens Wiklander ((token->db_objs->count - 1) * sizeof(TEE_UUID)), 373334316feSJens Wiklander TEE_USER_MEM_HINT_NO_FILL_ZERO); 374334316feSJens Wiklander if (!ptr) 375334316feSJens Wiklander return PKCS11_CKR_DEVICE_MEMORY; 376334316feSJens Wiklander 377334316feSJens Wiklander res = open_db_file(token, &db_hdl); 378334316feSJens Wiklander if (res) 379334316feSJens Wiklander goto out; 380334316feSJens Wiklander 381334316feSJens Wiklander res = TEE_SeekObjectData(db_hdl, sizeof(struct token_persistent_main), 382334316feSJens Wiklander TEE_DATA_SEEK_SET); 383334316feSJens Wiklander if (res) { 384334316feSJens Wiklander DMSG("Failed to read database"); 385334316feSJens Wiklander goto out; 386334316feSJens Wiklander } 387334316feSJens Wiklander 388334316feSJens Wiklander TEE_MemMove(ptr, token->db_objs, 389334316feSJens Wiklander sizeof(struct token_persistent_objs) + 390334316feSJens Wiklander idx * sizeof(TEE_UUID)); 391334316feSJens Wiklander 392334316feSJens Wiklander ptr->count--; 393334316feSJens Wiklander count = ptr->count - idx; 394334316feSJens Wiklander 395334316feSJens Wiklander TEE_MemMove(&ptr->uuids[idx], 396334316feSJens Wiklander &token->db_objs->uuids[idx + 1], 397334316feSJens Wiklander count * sizeof(TEE_UUID)); 398334316feSJens Wiklander 399334316feSJens Wiklander res = TEE_WriteObjectData(db_hdl, ptr, 400334316feSJens Wiklander sizeof(struct token_persistent_objs) + 401334316feSJens Wiklander ptr->count * sizeof(TEE_UUID)); 402334316feSJens Wiklander if (res) 403334316feSJens Wiklander DMSG("Failed to update database"); 404334316feSJens Wiklander TEE_Free(token->db_objs); 405334316feSJens Wiklander token->db_objs = ptr; 406334316feSJens Wiklander ptr = NULL; 407334316feSJens Wiklander 408334316feSJens Wiklander out: 409334316feSJens Wiklander TEE_CloseObject(db_hdl); 410334316feSJens Wiklander TEE_Free(ptr); 411334316feSJens Wiklander 412334316feSJens Wiklander return tee2pkcs_error(res); 413334316feSJens Wiklander } 414334316feSJens Wiklander 415334316feSJens Wiklander enum pkcs11_rc register_persistent_object(struct ck_token *token, 416334316feSJens Wiklander TEE_UUID *uuid) 417334316feSJens Wiklander { 418334316feSJens Wiklander TEE_ObjectHandle db_hdl = TEE_HANDLE_NULL; 419334316feSJens Wiklander TEE_Result res = TEE_ERROR_GENERIC; 420334316feSJens Wiklander void *ptr = NULL; 421334316feSJens Wiklander size_t size = 0; 422334316feSJens Wiklander int count = 0; 423334316feSJens Wiklander 424334316feSJens Wiklander if (get_persistent_obj_idx(token, uuid) >= 0) 425334316feSJens Wiklander TEE_Panic(0); 426334316feSJens Wiklander 427334316feSJens Wiklander count = token->db_objs->count; 428334316feSJens Wiklander ptr = TEE_Realloc(token->db_objs, 429334316feSJens Wiklander sizeof(struct token_persistent_objs) + 430334316feSJens Wiklander ((count + 1) * sizeof(TEE_UUID))); 431334316feSJens Wiklander if (!ptr) 432334316feSJens Wiklander return PKCS11_CKR_DEVICE_MEMORY; 433334316feSJens Wiklander 434334316feSJens Wiklander token->db_objs = ptr; 435334316feSJens Wiklander TEE_MemMove(token->db_objs->uuids + count, uuid, sizeof(TEE_UUID)); 436334316feSJens Wiklander 437334316feSJens Wiklander size = sizeof(struct token_persistent_main) + 438334316feSJens Wiklander sizeof(struct token_persistent_objs) + 439334316feSJens Wiklander count * sizeof(TEE_UUID); 440334316feSJens Wiklander 441334316feSJens Wiklander res = open_db_file(token, &db_hdl); 442334316feSJens Wiklander if (res) 443334316feSJens Wiklander goto out; 444334316feSJens Wiklander 445334316feSJens Wiklander res = TEE_TruncateObjectData(db_hdl, size + sizeof(TEE_UUID)); 446334316feSJens Wiklander if (res) 447334316feSJens Wiklander goto out; 448334316feSJens Wiklander 449334316feSJens Wiklander res = TEE_SeekObjectData(db_hdl, sizeof(struct token_persistent_main), 450334316feSJens Wiklander TEE_DATA_SEEK_SET); 451334316feSJens Wiklander if (res) 452334316feSJens Wiklander goto out; 453334316feSJens Wiklander 454334316feSJens Wiklander token->db_objs->count++; 455334316feSJens Wiklander 456334316feSJens Wiklander res = TEE_WriteObjectData(db_hdl, token->db_objs, 457334316feSJens Wiklander sizeof(struct token_persistent_objs) + 458334316feSJens Wiklander token->db_objs->count * sizeof(TEE_UUID)); 459334316feSJens Wiklander if (res) 460334316feSJens Wiklander token->db_objs->count--; 461334316feSJens Wiklander 462334316feSJens Wiklander out: 463334316feSJens Wiklander TEE_CloseObject(db_hdl); 464334316feSJens Wiklander 465334316feSJens Wiklander return tee2pkcs_error(res); 466334316feSJens Wiklander } 467334316feSJens Wiklander 468fa1ac767SRobin van der Gracht enum pkcs11_rc load_persistent_object_attributes(struct pkcs11_object *obj) 469fa1ac767SRobin van der Gracht { 470fa1ac767SRobin van der Gracht enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR; 471fa1ac767SRobin van der Gracht TEE_Result res = TEE_ERROR_GENERIC; 472fa1ac767SRobin van der Gracht TEE_ObjectHandle hdl = obj->attribs_hdl; 473fa1ac767SRobin van der Gracht TEE_ObjectInfo info = { }; 474fa1ac767SRobin van der Gracht struct obj_attrs *attr = NULL; 475*c7f1b4f7SJens Wiklander size_t read_bytes = 0; 476fa1ac767SRobin van der Gracht 477fa1ac767SRobin van der Gracht if (obj->attributes) 478fa1ac767SRobin van der Gracht return PKCS11_CKR_OK; 479fa1ac767SRobin van der Gracht 480fa1ac767SRobin van der Gracht if (hdl == TEE_HANDLE_NULL) { 481fa1ac767SRobin van der Gracht res = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE, 482fa1ac767SRobin van der Gracht obj->uuid, sizeof(*obj->uuid), 483fa1ac767SRobin van der Gracht TEE_DATA_FLAG_ACCESS_READ, &hdl); 484fa1ac767SRobin van der Gracht if (res) { 485fa1ac767SRobin van der Gracht EMSG("OpenPersistent failed %#"PRIx32, res); 486fa1ac767SRobin van der Gracht return tee2pkcs_error(res); 487fa1ac767SRobin van der Gracht } 488fa1ac767SRobin van der Gracht } 489fa1ac767SRobin van der Gracht 490fa1ac767SRobin van der Gracht TEE_MemFill(&info, 0, sizeof(info)); 491fa1ac767SRobin van der Gracht res = TEE_GetObjectInfo1(hdl, &info); 492fa1ac767SRobin van der Gracht if (res) { 493fa1ac767SRobin van der Gracht EMSG("GetObjectInfo failed %#"PRIx32, res); 494fa1ac767SRobin van der Gracht rc = tee2pkcs_error(res); 495fa1ac767SRobin van der Gracht goto out; 496fa1ac767SRobin van der Gracht } 497fa1ac767SRobin van der Gracht 498fa1ac767SRobin van der Gracht attr = TEE_Malloc(info.dataSize, TEE_MALLOC_FILL_ZERO); 499fa1ac767SRobin van der Gracht if (!attr) { 500fa1ac767SRobin van der Gracht rc = PKCS11_CKR_DEVICE_MEMORY; 501fa1ac767SRobin van der Gracht goto out; 502fa1ac767SRobin van der Gracht } 503fa1ac767SRobin van der Gracht 504fa1ac767SRobin van der Gracht res = TEE_ReadObjectData(hdl, attr, info.dataSize, &read_bytes); 505fa1ac767SRobin van der Gracht if (!res) { 506fa1ac767SRobin van der Gracht res = TEE_SeekObjectData(hdl, 0, TEE_DATA_SEEK_SET); 507fa1ac767SRobin van der Gracht if (res) 508fa1ac767SRobin van der Gracht EMSG("Seek to 0 failed %#"PRIx32, res); 509fa1ac767SRobin van der Gracht } 510fa1ac767SRobin van der Gracht 511fa1ac767SRobin van der Gracht if (res) { 512fa1ac767SRobin van der Gracht rc = tee2pkcs_error(res); 513*c7f1b4f7SJens Wiklander EMSG("Read %zu bytes, failed %#"PRIx32, 514fa1ac767SRobin van der Gracht read_bytes, res); 515fa1ac767SRobin van der Gracht goto out; 516fa1ac767SRobin van der Gracht } 517fa1ac767SRobin van der Gracht if (read_bytes != info.dataSize) { 518*c7f1b4f7SJens Wiklander EMSG("Read %zu bytes, expected %zu", 519fa1ac767SRobin van der Gracht read_bytes, info.dataSize); 520fa1ac767SRobin van der Gracht rc = PKCS11_CKR_GENERAL_ERROR; 521fa1ac767SRobin van der Gracht goto out; 522fa1ac767SRobin van der Gracht } 523fa1ac767SRobin van der Gracht 524fa1ac767SRobin van der Gracht obj->attributes = attr; 525fa1ac767SRobin van der Gracht attr = NULL; 526fa1ac767SRobin van der Gracht 527fa1ac767SRobin van der Gracht rc = PKCS11_CKR_OK; 528fa1ac767SRobin van der Gracht 529fa1ac767SRobin van der Gracht out: 530fa1ac767SRobin van der Gracht TEE_Free(attr); 531fa1ac767SRobin van der Gracht /* Close object only if it was open from this function */ 532fa1ac767SRobin van der Gracht if (obj->attribs_hdl == TEE_HANDLE_NULL) 533fa1ac767SRobin van der Gracht TEE_CloseObject(hdl); 534fa1ac767SRobin van der Gracht 535fa1ac767SRobin van der Gracht return rc; 536fa1ac767SRobin van der Gracht } 537fa1ac767SRobin van der Gracht 538fa1ac767SRobin van der Gracht void release_persistent_object_attributes(struct pkcs11_object *obj) 539fa1ac767SRobin van der Gracht { 540fa1ac767SRobin van der Gracht TEE_Free(obj->attributes); 541fa1ac767SRobin van der Gracht obj->attributes = NULL; 542fa1ac767SRobin van der Gracht } 543fa1ac767SRobin van der Gracht 544402d884aSRuchika Gupta enum pkcs11_rc update_persistent_object_attributes(struct pkcs11_object *obj) 545402d884aSRuchika Gupta { 546402d884aSRuchika Gupta TEE_Result res = TEE_ERROR_GENERIC; 547402d884aSRuchika Gupta TEE_ObjectHandle hdl = TEE_HANDLE_NULL; 548402d884aSRuchika Gupta uint32_t tee_obj_flags = TEE_DATA_FLAG_ACCESS_WRITE; 549402d884aSRuchika Gupta size_t size = 0; 550402d884aSRuchika Gupta 551402d884aSRuchika Gupta assert(obj && obj->attributes); 552402d884aSRuchika Gupta 553402d884aSRuchika Gupta res = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE, 554402d884aSRuchika Gupta obj->uuid, sizeof(*obj->uuid), 555402d884aSRuchika Gupta tee_obj_flags, &hdl); 556402d884aSRuchika Gupta if (res) { 557402d884aSRuchika Gupta EMSG("OpenPersistent failed %#"PRIx32, res); 558402d884aSRuchika Gupta return tee2pkcs_error(res); 559402d884aSRuchika Gupta } 560402d884aSRuchika Gupta 561402d884aSRuchika Gupta size = sizeof(struct obj_attrs) + obj->attributes->attrs_size; 562402d884aSRuchika Gupta 563402d884aSRuchika Gupta res = TEE_WriteObjectData(hdl, obj->attributes, size); 564402d884aSRuchika Gupta if (res) 565402d884aSRuchika Gupta goto out; 566402d884aSRuchika Gupta 567402d884aSRuchika Gupta res = TEE_TruncateObjectData(hdl, size); 568402d884aSRuchika Gupta 569402d884aSRuchika Gupta out: 570402d884aSRuchika Gupta TEE_CloseObject(hdl); 571402d884aSRuchika Gupta return tee2pkcs_error(res); 572402d884aSRuchika Gupta } 573402d884aSRuchika Gupta 57460659a86SEtienne Carriere /* 575c84ccd0aSEtienne Carriere * Return the token instance, either initialized from reset or initialized 576c84ccd0aSEtienne Carriere * from the token persistent state if found. 577c84ccd0aSEtienne Carriere */ 578c84ccd0aSEtienne Carriere struct ck_token *init_persistent_db(unsigned int token_id) 579c84ccd0aSEtienne Carriere { 580c84ccd0aSEtienne Carriere struct ck_token *token = get_token(token_id); 581c84ccd0aSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 582c84ccd0aSEtienne Carriere TEE_ObjectHandle db_hdl = TEE_HANDLE_NULL; 58360659a86SEtienne Carriere /* Copy persistent database: main db and object db */ 584c84ccd0aSEtienne Carriere struct token_persistent_main *db_main = NULL; 585334316feSJens Wiklander struct token_persistent_objs *db_objs = NULL; 586334316feSJens Wiklander void *ptr = NULL; 587c84ccd0aSEtienne Carriere 588c84ccd0aSEtienne Carriere if (!token) 589c84ccd0aSEtienne Carriere return NULL; 590c84ccd0aSEtienne Carriere 591334316feSJens Wiklander LIST_INIT(&token->object_list); 592334316feSJens Wiklander 593c84ccd0aSEtienne Carriere db_main = TEE_Malloc(sizeof(*db_main), TEE_MALLOC_FILL_ZERO); 594334316feSJens Wiklander db_objs = TEE_Malloc(sizeof(*db_objs), TEE_MALLOC_FILL_ZERO); 595334316feSJens Wiklander if (!db_main || !db_objs) 596c84ccd0aSEtienne Carriere goto error; 597c84ccd0aSEtienne Carriere 59860659a86SEtienne Carriere res = open_db_file(token, &db_hdl); 599c84ccd0aSEtienne Carriere 600c84ccd0aSEtienne Carriere if (res == TEE_SUCCESS) { 601*c7f1b4f7SJens Wiklander size_t size = 0; 602334316feSJens Wiklander size_t idx = 0; 603c84ccd0aSEtienne Carriere 604c84ccd0aSEtienne Carriere IMSG("PKCS11 token %u: load db", token_id); 605c84ccd0aSEtienne Carriere 606c84ccd0aSEtienne Carriere size = sizeof(*db_main); 607c84ccd0aSEtienne Carriere res = TEE_ReadObjectData(db_hdl, db_main, size, &size); 608c84ccd0aSEtienne Carriere if (res || size != sizeof(*db_main)) 609c84ccd0aSEtienne Carriere TEE_Panic(0); 610334316feSJens Wiklander 611334316feSJens Wiklander size = sizeof(*db_objs); 612334316feSJens Wiklander res = TEE_ReadObjectData(db_hdl, db_objs, size, &size); 613334316feSJens Wiklander if (res || size != sizeof(*db_objs)) 614334316feSJens Wiklander TEE_Panic(0); 615334316feSJens Wiklander 616974adb9fSRobin van der Gracht if (db_objs->count > 0) { 617334316feSJens Wiklander size += db_objs->count * sizeof(TEE_UUID); 618334316feSJens Wiklander ptr = TEE_Realloc(db_objs, size); 619334316feSJens Wiklander if (!ptr) 620334316feSJens Wiklander goto error; 621334316feSJens Wiklander 622334316feSJens Wiklander db_objs = ptr; 623a3c511dfSRobin van der Gracht size -= sizeof(*db_objs); 624974adb9fSRobin van der Gracht res = TEE_ReadObjectData(db_hdl, db_objs->uuids, size, 625974adb9fSRobin van der Gracht &size); 626334316feSJens Wiklander if (res || size != (db_objs->count * sizeof(TEE_UUID))) 627334316feSJens Wiklander TEE_Panic(0); 628974adb9fSRobin van der Gracht } 629334316feSJens Wiklander 630334316feSJens Wiklander for (idx = 0; idx < db_objs->count; idx++) { 631334316feSJens Wiklander /* Create an empty object instance */ 632334316feSJens Wiklander struct pkcs11_object *obj = NULL; 633334316feSJens Wiklander TEE_UUID *uuid = NULL; 634334316feSJens Wiklander 635334316feSJens Wiklander uuid = TEE_Malloc(sizeof(TEE_UUID), 636334316feSJens Wiklander TEE_USER_MEM_HINT_NO_FILL_ZERO); 637334316feSJens Wiklander if (!uuid) 638334316feSJens Wiklander goto error; 639334316feSJens Wiklander 640334316feSJens Wiklander TEE_MemMove(uuid, &db_objs->uuids[idx], sizeof(*uuid)); 641334316feSJens Wiklander 642bc555ee0SVesa Jääskeläinen obj = create_token_object(NULL, uuid, token); 643334316feSJens Wiklander if (!obj) 644334316feSJens Wiklander TEE_Panic(0); 645334316feSJens Wiklander 646334316feSJens Wiklander LIST_INSERT_HEAD(&token->object_list, obj, link); 647334316feSJens Wiklander } 648334316feSJens Wiklander 649c84ccd0aSEtienne Carriere } else if (res == TEE_ERROR_ITEM_NOT_FOUND) { 65060659a86SEtienne Carriere char file[PERSISTENT_OBJECT_ID_LEN] = { }; 65160659a86SEtienne Carriere 652c84ccd0aSEtienne Carriere IMSG("PKCS11 token %u: init db", token_id); 653c84ccd0aSEtienne Carriere 654c84ccd0aSEtienne Carriere TEE_MemFill(db_main, 0, sizeof(*db_main)); 655c84ccd0aSEtienne Carriere TEE_MemFill(db_main->label, '*', sizeof(db_main->label)); 656c84ccd0aSEtienne Carriere 657c84ccd0aSEtienne Carriere db_main->flags = PKCS11_CKFT_SO_PIN_TO_BE_CHANGED | 658c84ccd0aSEtienne Carriere PKCS11_CKFT_USER_PIN_TO_BE_CHANGED | 659c84ccd0aSEtienne Carriere PKCS11_CKFT_RNG | 660c84ccd0aSEtienne Carriere PKCS11_CKFT_LOGIN_REQUIRED; 661c84ccd0aSEtienne Carriere 66260659a86SEtienne Carriere res = get_db_file_name(token, file, sizeof(file)); 66360659a86SEtienne Carriere if (res) 66460659a86SEtienne Carriere TEE_Panic(0); 66560659a86SEtienne Carriere 666334316feSJens Wiklander /* 667334316feSJens Wiklander * Object stores persistent state + persistent object 668334316feSJens Wiklander * references. 669334316feSJens Wiklander */ 670c84ccd0aSEtienne Carriere res = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE, 67160659a86SEtienne Carriere file, sizeof(file), 672c84ccd0aSEtienne Carriere TEE_DATA_FLAG_ACCESS_READ | 673c84ccd0aSEtienne Carriere TEE_DATA_FLAG_ACCESS_WRITE, 674c84ccd0aSEtienne Carriere TEE_HANDLE_NULL, 675c84ccd0aSEtienne Carriere db_main, sizeof(*db_main), 676c84ccd0aSEtienne Carriere &db_hdl); 677c84ccd0aSEtienne Carriere if (res) { 67859a5257eSEtienne Carriere EMSG("Failed to create db: %#"PRIx32, res); 679c84ccd0aSEtienne Carriere goto error; 680c84ccd0aSEtienne Carriere } 681334316feSJens Wiklander 682334316feSJens Wiklander res = TEE_TruncateObjectData(db_hdl, sizeof(*db_main) + 683334316feSJens Wiklander sizeof(*db_objs)); 684334316feSJens Wiklander if (res) 685334316feSJens Wiklander TEE_Panic(0); 686334316feSJens Wiklander 687334316feSJens Wiklander res = TEE_SeekObjectData(db_hdl, sizeof(*db_main), 688334316feSJens Wiklander TEE_DATA_SEEK_SET); 689334316feSJens Wiklander if (res) 690334316feSJens Wiklander TEE_Panic(0); 691334316feSJens Wiklander 692334316feSJens Wiklander db_objs->count = 0; 693334316feSJens Wiklander res = TEE_WriteObjectData(db_hdl, db_objs, sizeof(*db_objs)); 694334316feSJens Wiklander if (res) 695334316feSJens Wiklander TEE_Panic(0); 696334316feSJens Wiklander 697c84ccd0aSEtienne Carriere } else { 698c84ccd0aSEtienne Carriere goto error; 699c84ccd0aSEtienne Carriere } 700c84ccd0aSEtienne Carriere 701c84ccd0aSEtienne Carriere token->db_main = db_main; 702334316feSJens Wiklander token->db_objs = db_objs; 703c84ccd0aSEtienne Carriere TEE_CloseObject(db_hdl); 704c84ccd0aSEtienne Carriere 705c84ccd0aSEtienne Carriere return token; 706c84ccd0aSEtienne Carriere 707c84ccd0aSEtienne Carriere error: 708c84ccd0aSEtienne Carriere TEE_Free(db_main); 709334316feSJens Wiklander TEE_Free(db_objs); 710c84ccd0aSEtienne Carriere if (db_hdl != TEE_HANDLE_NULL) 711c84ccd0aSEtienne Carriere TEE_CloseObject(db_hdl); 712c84ccd0aSEtienne Carriere 713c84ccd0aSEtienne Carriere return NULL; 714c84ccd0aSEtienne Carriere } 715