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 13c84ccd0aSEtienne Carriere #include "pkcs11_token.h" 14c84ccd0aSEtienne Carriere #include "pkcs11_helpers.h" 15c84ccd0aSEtienne Carriere 16*60659a86SEtienne Carriere #define PERSISTENT_OBJECT_ID_LEN 32 17*60659a86SEtienne Carriere 18*60659a86SEtienne Carriere /* 19*60659a86SEtienne Carriere * Token persistent objects 20*60659a86SEtienne Carriere */ 21*60659a86SEtienne Carriere static TEE_Result get_db_file_name(struct ck_token *token, 22*60659a86SEtienne Carriere char *name, size_t size) 23c84ccd0aSEtienne Carriere { 24*60659a86SEtienne Carriere int n = snprintf(name, size, "token.db.%u", get_token_id(token)); 25*60659a86SEtienne Carriere 26*60659a86SEtienne Carriere if (n < 0 || (size_t)n >= size) 27*60659a86SEtienne Carriere return TEE_ERROR_SECURITY; 28*60659a86SEtienne Carriere else 29*60659a86SEtienne Carriere return TEE_SUCCESS; 30*60659a86SEtienne Carriere } 31*60659a86SEtienne Carriere 32*60659a86SEtienne Carriere static TEE_Result open_db_file(struct ck_token *token, 33*60659a86SEtienne Carriere TEE_ObjectHandle *out_hdl) 34*60659a86SEtienne Carriere { 35*60659a86SEtienne Carriere char file[PERSISTENT_OBJECT_ID_LEN] = { }; 36*60659a86SEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 37*60659a86SEtienne Carriere 38*60659a86SEtienne Carriere res = get_db_file_name(token, file, sizeof(file)); 39*60659a86SEtienne Carriere if (res) 40*60659a86SEtienne Carriere return res; 41*60659a86SEtienne Carriere 42*60659a86SEtienne Carriere return TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE, file, sizeof(file), 43*60659a86SEtienne Carriere TEE_DATA_FLAG_ACCESS_READ | 44*60659a86SEtienne Carriere TEE_DATA_FLAG_ACCESS_WRITE, 45*60659a86SEtienne Carriere out_hdl); 46*60659a86SEtienne Carriere } 47*60659a86SEtienne Carriere 48*60659a86SEtienne Carriere static TEE_Result get_pin_file_name(struct ck_token *token, 49*60659a86SEtienne Carriere enum pkcs11_user_type user, 50*60659a86SEtienne Carriere char *name, size_t size) 51*60659a86SEtienne Carriere { 52*60659a86SEtienne Carriere int n = snprintf(name, size, 53*60659a86SEtienne Carriere "token.db.%u-pin%d", get_token_id(token), user); 54*60659a86SEtienne Carriere 55*60659a86SEtienne Carriere if (n < 0 || (size_t)n >= size) 56*60659a86SEtienne Carriere return TEE_ERROR_SECURITY; 57*60659a86SEtienne Carriere else 58*60659a86SEtienne Carriere return TEE_SUCCESS; 59*60659a86SEtienne Carriere } 60*60659a86SEtienne Carriere 61*60659a86SEtienne Carriere static TEE_Result open_pin_file(struct ck_token *token, 62*60659a86SEtienne Carriere enum pkcs11_user_type user, 63*60659a86SEtienne Carriere TEE_ObjectHandle *out_hdl) 64*60659a86SEtienne Carriere { 65*60659a86SEtienne Carriere char file[PERSISTENT_OBJECT_ID_LEN] = { }; 66*60659a86SEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 67*60659a86SEtienne Carriere 68*60659a86SEtienne Carriere res = get_pin_file_name(token, user, file, sizeof(file)); 69*60659a86SEtienne Carriere if (res) 70*60659a86SEtienne Carriere return res; 71*60659a86SEtienne Carriere 72*60659a86SEtienne Carriere return TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE, file, sizeof(file), 73*60659a86SEtienne Carriere 0, out_hdl); 74c84ccd0aSEtienne Carriere } 75c84ccd0aSEtienne Carriere 76c84ccd0aSEtienne Carriere static void init_pin_keys(struct ck_token *token, unsigned int uid) 77c84ccd0aSEtienne Carriere { 78c84ccd0aSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 79c84ccd0aSEtienne Carriere TEE_ObjectHandle key_hdl = TEE_HANDLE_NULL; 80*60659a86SEtienne Carriere enum pkcs11_user_type user = uid; 81c84ccd0aSEtienne Carriere 82*60659a86SEtienne Carriere res = open_pin_file(token, user, &key_hdl); 83c84ccd0aSEtienne Carriere 84*60659a86SEtienne Carriere if (res == TEE_SUCCESS) 85*60659a86SEtienne Carriere DMSG("PIN key found"); 86c84ccd0aSEtienne Carriere 87c84ccd0aSEtienne Carriere if (res == TEE_ERROR_ITEM_NOT_FOUND) { 88c84ccd0aSEtienne Carriere TEE_Attribute attr = { }; 89c84ccd0aSEtienne Carriere TEE_ObjectHandle hdl = TEE_HANDLE_NULL; 90*60659a86SEtienne Carriere uint8_t pin_key[16] = { }; 91*60659a86SEtienne Carriere char file[PERSISTENT_OBJECT_ID_LEN] = { }; 92c84ccd0aSEtienne Carriere 93c84ccd0aSEtienne Carriere TEE_MemFill(&attr, 0, sizeof(attr)); 94c84ccd0aSEtienne Carriere 95c84ccd0aSEtienne Carriere TEE_GenerateRandom(pin_key, sizeof(pin_key)); 96c84ccd0aSEtienne Carriere TEE_InitRefAttribute(&attr, TEE_ATTR_SECRET_VALUE, 97c84ccd0aSEtienne Carriere pin_key, sizeof(pin_key)); 98c84ccd0aSEtienne Carriere 99c84ccd0aSEtienne Carriere res = TEE_AllocateTransientObject(TEE_TYPE_AES, 128, &hdl); 100c84ccd0aSEtienne Carriere if (res) 101c84ccd0aSEtienne Carriere TEE_Panic(0); 102c84ccd0aSEtienne Carriere 103c84ccd0aSEtienne Carriere res = TEE_PopulateTransientObject(hdl, &attr, 1); 104c84ccd0aSEtienne Carriere if (res) 105c84ccd0aSEtienne Carriere TEE_Panic(0); 106c84ccd0aSEtienne Carriere 107*60659a86SEtienne Carriere res = get_pin_file_name(token, user, file, sizeof(file)); 108*60659a86SEtienne Carriere if (res) 109*60659a86SEtienne Carriere TEE_Panic(0); 110*60659a86SEtienne Carriere 111c84ccd0aSEtienne Carriere res = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE, 112c84ccd0aSEtienne Carriere file, sizeof(file), 0, hdl, 113c84ccd0aSEtienne Carriere pin_key, sizeof(pin_key), 114c84ccd0aSEtienne Carriere &key_hdl); 115c84ccd0aSEtienne Carriere TEE_CloseObject(hdl); 116c84ccd0aSEtienne Carriere 117c84ccd0aSEtienne Carriere if (res == TEE_SUCCESS) 118*60659a86SEtienne Carriere DMSG("Token %u: PIN key created", get_token_id(token)); 119c84ccd0aSEtienne Carriere } 120c84ccd0aSEtienne Carriere 121c84ccd0aSEtienne Carriere if (res) 122c84ccd0aSEtienne Carriere TEE_Panic(res); 123c84ccd0aSEtienne Carriere 124c84ccd0aSEtienne Carriere TEE_CloseObject(key_hdl); 125c84ccd0aSEtienne Carriere } 126c84ccd0aSEtienne Carriere 127c84ccd0aSEtienne Carriere /* 128*60659a86SEtienne Carriere * Release resources relate to persistent database 129*60659a86SEtienne Carriere */ 130*60659a86SEtienne Carriere void close_persistent_db(struct ck_token *token __unused) 131*60659a86SEtienne Carriere { 132*60659a86SEtienne Carriere } 133*60659a86SEtienne Carriere 134*60659a86SEtienne Carriere /* 135c84ccd0aSEtienne Carriere * Return the token instance, either initialized from reset or initialized 136c84ccd0aSEtienne Carriere * from the token persistent state if found. 137c84ccd0aSEtienne Carriere */ 138c84ccd0aSEtienne Carriere struct ck_token *init_persistent_db(unsigned int token_id) 139c84ccd0aSEtienne Carriere { 140c84ccd0aSEtienne Carriere struct ck_token *token = get_token(token_id); 141c84ccd0aSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 142c84ccd0aSEtienne Carriere TEE_ObjectHandle db_hdl = TEE_HANDLE_NULL; 143*60659a86SEtienne Carriere /* Copy persistent database: main db and object db */ 144c84ccd0aSEtienne Carriere struct token_persistent_main *db_main = NULL; 145c84ccd0aSEtienne Carriere 146c84ccd0aSEtienne Carriere if (!token) 147c84ccd0aSEtienne Carriere return NULL; 148c84ccd0aSEtienne Carriere 1499dbdd8cdSEtienne Carriere init_pin_keys(token, PKCS11_CKU_SO); 1509dbdd8cdSEtienne Carriere init_pin_keys(token, PKCS11_CKU_USER); 1519dbdd8cdSEtienne Carriere COMPILE_TIME_ASSERT(PKCS11_CKU_SO == 0 && PKCS11_CKU_USER == 1 && 1529dbdd8cdSEtienne Carriere PKCS11_MAX_USERS >= 2); 153c84ccd0aSEtienne Carriere 154c84ccd0aSEtienne Carriere db_main = TEE_Malloc(sizeof(*db_main), TEE_MALLOC_FILL_ZERO); 155c84ccd0aSEtienne Carriere if (!db_main) 156c84ccd0aSEtienne Carriere goto error; 157c84ccd0aSEtienne Carriere 158*60659a86SEtienne Carriere res = open_db_file(token, &db_hdl); 159c84ccd0aSEtienne Carriere 160c84ccd0aSEtienne Carriere if (res == TEE_SUCCESS) { 161c84ccd0aSEtienne Carriere uint32_t size = 0; 162c84ccd0aSEtienne Carriere 163c84ccd0aSEtienne Carriere IMSG("PKCS11 token %u: load db", token_id); 164c84ccd0aSEtienne Carriere 165c84ccd0aSEtienne Carriere size = sizeof(*db_main); 166c84ccd0aSEtienne Carriere res = TEE_ReadObjectData(db_hdl, db_main, size, &size); 167c84ccd0aSEtienne Carriere if (res || size != sizeof(*db_main)) 168c84ccd0aSEtienne Carriere TEE_Panic(0); 169c84ccd0aSEtienne Carriere } else if (res == TEE_ERROR_ITEM_NOT_FOUND) { 170*60659a86SEtienne Carriere char file[PERSISTENT_OBJECT_ID_LEN] = { }; 171*60659a86SEtienne Carriere 172c84ccd0aSEtienne Carriere IMSG("PKCS11 token %u: init db", token_id); 173c84ccd0aSEtienne Carriere 174c84ccd0aSEtienne Carriere TEE_MemFill(db_main, 0, sizeof(*db_main)); 175c84ccd0aSEtienne Carriere TEE_MemFill(db_main->label, '*', sizeof(db_main->label)); 176c84ccd0aSEtienne Carriere 177c84ccd0aSEtienne Carriere db_main->flags = PKCS11_CKFT_SO_PIN_TO_BE_CHANGED | 178c84ccd0aSEtienne Carriere PKCS11_CKFT_USER_PIN_TO_BE_CHANGED | 179c84ccd0aSEtienne Carriere PKCS11_CKFT_RNG | 180c84ccd0aSEtienne Carriere PKCS11_CKFT_DUAL_CRYPTO_OPERATIONS | 181c84ccd0aSEtienne Carriere PKCS11_CKFT_LOGIN_REQUIRED; 182c84ccd0aSEtienne Carriere 183*60659a86SEtienne Carriere res = get_db_file_name(token, file, sizeof(file)); 184*60659a86SEtienne Carriere if (res) 185*60659a86SEtienne Carriere TEE_Panic(0); 186*60659a86SEtienne Carriere 187*60659a86SEtienne Carriere /* 2 files: persistent state + persistent object references */ 188c84ccd0aSEtienne Carriere res = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE, 189*60659a86SEtienne Carriere file, sizeof(file), 190c84ccd0aSEtienne Carriere TEE_DATA_FLAG_ACCESS_READ | 191c84ccd0aSEtienne Carriere TEE_DATA_FLAG_ACCESS_WRITE, 192c84ccd0aSEtienne Carriere TEE_HANDLE_NULL, 193c84ccd0aSEtienne Carriere db_main, sizeof(*db_main), 194c84ccd0aSEtienne Carriere &db_hdl); 195c84ccd0aSEtienne Carriere if (res) { 196c84ccd0aSEtienne Carriere EMSG("Failed to create db: %"PRIx32, res); 197c84ccd0aSEtienne Carriere goto error; 198c84ccd0aSEtienne Carriere } 199c84ccd0aSEtienne Carriere } else { 200c84ccd0aSEtienne Carriere goto error; 201c84ccd0aSEtienne Carriere } 202c84ccd0aSEtienne Carriere 203c84ccd0aSEtienne Carriere token->db_main = db_main; 204c84ccd0aSEtienne Carriere TEE_CloseObject(db_hdl); 205c84ccd0aSEtienne Carriere 206c84ccd0aSEtienne Carriere return token; 207c84ccd0aSEtienne Carriere 208c84ccd0aSEtienne Carriere error: 209c84ccd0aSEtienne Carriere TEE_Free(db_main); 210c84ccd0aSEtienne Carriere if (db_hdl != TEE_HANDLE_NULL) 211c84ccd0aSEtienne Carriere TEE_CloseObject(db_hdl); 212c84ccd0aSEtienne Carriere 213c84ccd0aSEtienne Carriere return NULL; 214c84ccd0aSEtienne Carriere } 215