1*5baee69aSJens Wiklander /* 2*5baee69aSJens Wiklander * Copyright (c) 2017, Linaro Limited 3*5baee69aSJens Wiklander * 4*5baee69aSJens Wiklander * SPDX-License-Identifier: BSD-2-Clause 5*5baee69aSJens Wiklander */ 6*5baee69aSJens Wiklander 7*5baee69aSJens Wiklander #include <bitstring.h> 8*5baee69aSJens Wiklander #include <crypto/crypto.h> 9*5baee69aSJens Wiklander #include <kernel/msg_param.h> 10*5baee69aSJens Wiklander #include <kernel/mutex.h> 11*5baee69aSJens Wiklander #include <kernel/refcount.h> 12*5baee69aSJens Wiklander #include <kernel/thread.h> 13*5baee69aSJens Wiklander #include <optee_msg_supplicant.h> 14*5baee69aSJens Wiklander #include <string.h> 15*5baee69aSJens Wiklander #include <tee_api_defines_extensions.h> 16*5baee69aSJens Wiklander #include <tee/tadb.h> 17*5baee69aSJens Wiklander #include <tee/tee_fs.h> 18*5baee69aSJens Wiklander #include <tee/tee_fs_rpc.h> 19*5baee69aSJens Wiklander #include <tee/tee_pobj.h> 20*5baee69aSJens Wiklander #include <tee/tee_svc_storage.h> 21*5baee69aSJens Wiklander #include <utee_defines.h> 22*5baee69aSJens Wiklander 23*5baee69aSJens Wiklander #define TADB_MAX_BUFFER_SIZE (64U * 1024) 24*5baee69aSJens Wiklander 25*5baee69aSJens Wiklander #define TADB_AUTH_ENC_ALG TEE_ALG_AES_GCM 26*5baee69aSJens Wiklander #define TADB_IV_SIZE TEE_AES_BLOCK_SIZE 27*5baee69aSJens Wiklander #define TADB_TAG_SIZE TEE_AES_BLOCK_SIZE 28*5baee69aSJens Wiklander #define TADB_KEY_SIZE TEE_AES_MAX_KEY_SIZE 29*5baee69aSJens Wiklander 30*5baee69aSJens Wiklander struct tee_tadb_dir { 31*5baee69aSJens Wiklander const struct tee_file_operations *ops; 32*5baee69aSJens Wiklander struct tee_file_handle *fh; 33*5baee69aSJens Wiklander int nbits; 34*5baee69aSJens Wiklander bitstr_t *files; 35*5baee69aSJens Wiklander }; 36*5baee69aSJens Wiklander 37*5baee69aSJens Wiklander struct tadb_entry { 38*5baee69aSJens Wiklander struct tee_tadb_property prop; 39*5baee69aSJens Wiklander uint32_t file_number; 40*5baee69aSJens Wiklander uint8_t iv[TADB_IV_SIZE]; 41*5baee69aSJens Wiklander uint8_t tag[TADB_TAG_SIZE]; 42*5baee69aSJens Wiklander uint8_t key[TADB_KEY_SIZE]; 43*5baee69aSJens Wiklander }; 44*5baee69aSJens Wiklander 45*5baee69aSJens Wiklander struct tadb_header { 46*5baee69aSJens Wiklander uint32_t opaque_len; 47*5baee69aSJens Wiklander uint8_t opaque[]; 48*5baee69aSJens Wiklander }; 49*5baee69aSJens Wiklander 50*5baee69aSJens Wiklander struct tee_tadb_ta_write { 51*5baee69aSJens Wiklander struct tee_tadb_dir *db; 52*5baee69aSJens Wiklander int fd; 53*5baee69aSJens Wiklander struct tadb_entry entry; 54*5baee69aSJens Wiklander size_t pos; 55*5baee69aSJens Wiklander void *ctx; 56*5baee69aSJens Wiklander }; 57*5baee69aSJens Wiklander 58*5baee69aSJens Wiklander struct tee_tadb_ta_read { 59*5baee69aSJens Wiklander struct tee_tadb_dir *db; 60*5baee69aSJens Wiklander int fd; 61*5baee69aSJens Wiklander struct tadb_entry entry; 62*5baee69aSJens Wiklander size_t pos; 63*5baee69aSJens Wiklander void *ctx; 64*5baee69aSJens Wiklander uint64_t ta_cookie; 65*5baee69aSJens Wiklander struct mobj *ta_mobj; 66*5baee69aSJens Wiklander uint8_t *ta_buf; 67*5baee69aSJens Wiklander }; 68*5baee69aSJens Wiklander 69*5baee69aSJens Wiklander static const char tadb_obj_id[] = "ta.db"; 70*5baee69aSJens Wiklander static struct tee_tadb_dir *tadb_db; 71*5baee69aSJens Wiklander static struct refcount tadb_db_refc; 72*5baee69aSJens Wiklander static struct mutex tadb_mutex = MUTEX_INITIALIZER; 73*5baee69aSJens Wiklander 74*5baee69aSJens Wiklander static void file_num_to_str(char *buf, size_t blen, uint32_t file_number) 75*5baee69aSJens Wiklander { 76*5baee69aSJens Wiklander snprintf(buf, blen, "%" PRIu32 ".ta", file_number); 77*5baee69aSJens Wiklander } 78*5baee69aSJens Wiklander 79*5baee69aSJens Wiklander static bool is_null_uuid(const TEE_UUID *uuid) 80*5baee69aSJens Wiklander { 81*5baee69aSJens Wiklander const TEE_UUID null_uuid = { 0 }; 82*5baee69aSJens Wiklander 83*5baee69aSJens Wiklander return !memcmp(uuid, &null_uuid, sizeof(*uuid)); 84*5baee69aSJens Wiklander } 85*5baee69aSJens Wiklander 86*5baee69aSJens Wiklander static TEE_Result ta_operation_open(unsigned int cmd, uint32_t file_number, 87*5baee69aSJens Wiklander int *fd) 88*5baee69aSJens Wiklander { 89*5baee69aSJens Wiklander struct mobj *mobj; 90*5baee69aSJens Wiklander TEE_Result res; 91*5baee69aSJens Wiklander void *va; 92*5baee69aSJens Wiklander uint64_t cookie; 93*5baee69aSJens Wiklander struct optee_msg_param params[] = { 94*5baee69aSJens Wiklander [0] = { .attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT, 95*5baee69aSJens Wiklander .u.value.a = cmd }, 96*5baee69aSJens Wiklander [2] = { .attr = OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT } 97*5baee69aSJens Wiklander }; 98*5baee69aSJens Wiklander 99*5baee69aSJens Wiklander va = tee_fs_rpc_cache_alloc(TEE_FS_NAME_MAX, &mobj, &cookie); 100*5baee69aSJens Wiklander if (!va) 101*5baee69aSJens Wiklander return TEE_ERROR_OUT_OF_MEMORY; 102*5baee69aSJens Wiklander 103*5baee69aSJens Wiklander if (!msg_param_init_memparam(params + 1, mobj, 0, TEE_FS_NAME_MAX, 104*5baee69aSJens Wiklander cookie, MSG_PARAM_MEM_DIR_IN)) 105*5baee69aSJens Wiklander return TEE_ERROR_BAD_STATE; 106*5baee69aSJens Wiklander 107*5baee69aSJens Wiklander file_num_to_str(va, TEE_FS_NAME_MAX, file_number); 108*5baee69aSJens Wiklander 109*5baee69aSJens Wiklander res = thread_rpc_cmd(OPTEE_MSG_RPC_CMD_FS, ARRAY_SIZE(params), params); 110*5baee69aSJens Wiklander if (!res) 111*5baee69aSJens Wiklander *fd = params[2].u.value.a; 112*5baee69aSJens Wiklander 113*5baee69aSJens Wiklander return res; 114*5baee69aSJens Wiklander } 115*5baee69aSJens Wiklander 116*5baee69aSJens Wiklander static TEE_Result ta_operation_remove(uint32_t file_number) 117*5baee69aSJens Wiklander { 118*5baee69aSJens Wiklander struct mobj *mobj; 119*5baee69aSJens Wiklander void *va; 120*5baee69aSJens Wiklander uint64_t cookie; 121*5baee69aSJens Wiklander struct optee_msg_param params[2] = { 122*5baee69aSJens Wiklander [0] = { .attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT, 123*5baee69aSJens Wiklander .u.value.a = OPTEE_MRF_REMOVE }, 124*5baee69aSJens Wiklander }; 125*5baee69aSJens Wiklander 126*5baee69aSJens Wiklander va = tee_fs_rpc_cache_alloc(TEE_FS_NAME_MAX, &mobj, &cookie); 127*5baee69aSJens Wiklander if (!va) 128*5baee69aSJens Wiklander return TEE_ERROR_OUT_OF_MEMORY; 129*5baee69aSJens Wiklander 130*5baee69aSJens Wiklander if (!msg_param_init_memparam(params + 1, mobj, 0, TEE_FS_NAME_MAX, 131*5baee69aSJens Wiklander cookie, MSG_PARAM_MEM_DIR_IN)) 132*5baee69aSJens Wiklander return TEE_ERROR_BAD_STATE; 133*5baee69aSJens Wiklander 134*5baee69aSJens Wiklander file_num_to_str(va, TEE_FS_NAME_MAX, file_number); 135*5baee69aSJens Wiklander 136*5baee69aSJens Wiklander return thread_rpc_cmd(OPTEE_MSG_RPC_CMD_FS, ARRAY_SIZE(params), params); 137*5baee69aSJens Wiklander } 138*5baee69aSJens Wiklander 139*5baee69aSJens Wiklander static TEE_Result maybe_grow_files(struct tee_tadb_dir *db, int idx) 140*5baee69aSJens Wiklander { 141*5baee69aSJens Wiklander void *p; 142*5baee69aSJens Wiklander 143*5baee69aSJens Wiklander if (idx < db->nbits) 144*5baee69aSJens Wiklander return TEE_SUCCESS; 145*5baee69aSJens Wiklander 146*5baee69aSJens Wiklander p = realloc(db->files, bitstr_size(idx + 1)); 147*5baee69aSJens Wiklander if (!p) 148*5baee69aSJens Wiklander return TEE_ERROR_OUT_OF_MEMORY; 149*5baee69aSJens Wiklander db->files = p; 150*5baee69aSJens Wiklander 151*5baee69aSJens Wiklander bit_nclear(db->files, db->nbits, idx); 152*5baee69aSJens Wiklander db->nbits = idx + 1; 153*5baee69aSJens Wiklander 154*5baee69aSJens Wiklander return TEE_SUCCESS; 155*5baee69aSJens Wiklander } 156*5baee69aSJens Wiklander 157*5baee69aSJens Wiklander static TEE_Result set_file(struct tee_tadb_dir *db, int idx) 158*5baee69aSJens Wiklander { 159*5baee69aSJens Wiklander TEE_Result res = maybe_grow_files(db, idx); 160*5baee69aSJens Wiklander 161*5baee69aSJens Wiklander if (!res) 162*5baee69aSJens Wiklander bit_set(db->files, idx); 163*5baee69aSJens Wiklander 164*5baee69aSJens Wiklander return res; 165*5baee69aSJens Wiklander } 166*5baee69aSJens Wiklander 167*5baee69aSJens Wiklander static void clear_file(struct tee_tadb_dir *db, int idx) 168*5baee69aSJens Wiklander { 169*5baee69aSJens Wiklander if (idx < db->nbits) 170*5baee69aSJens Wiklander bit_clear(db->files, idx); 171*5baee69aSJens Wiklander } 172*5baee69aSJens Wiklander 173*5baee69aSJens Wiklander static bool test_file(struct tee_tadb_dir *db, int idx) 174*5baee69aSJens Wiklander { 175*5baee69aSJens Wiklander if (idx < db->nbits) 176*5baee69aSJens Wiklander return bit_test(db->files, idx); 177*5baee69aSJens Wiklander 178*5baee69aSJens Wiklander return false; 179*5baee69aSJens Wiklander } 180*5baee69aSJens Wiklander 181*5baee69aSJens Wiklander static TEE_Result read_ent(struct tee_tadb_dir *db, size_t idx, 182*5baee69aSJens Wiklander struct tadb_entry *entry) 183*5baee69aSJens Wiklander { 184*5baee69aSJens Wiklander size_t l = sizeof(*entry); 185*5baee69aSJens Wiklander TEE_Result res = db->ops->read(db->fh, idx * l, entry, &l); 186*5baee69aSJens Wiklander 187*5baee69aSJens Wiklander if (!res && l != sizeof(*entry)) 188*5baee69aSJens Wiklander return TEE_ERROR_ITEM_NOT_FOUND; 189*5baee69aSJens Wiklander 190*5baee69aSJens Wiklander return res; 191*5baee69aSJens Wiklander } 192*5baee69aSJens Wiklander 193*5baee69aSJens Wiklander static TEE_Result write_ent(struct tee_tadb_dir *db, size_t idx, 194*5baee69aSJens Wiklander const struct tadb_entry *entry) 195*5baee69aSJens Wiklander { 196*5baee69aSJens Wiklander const size_t l = sizeof(*entry); 197*5baee69aSJens Wiklander 198*5baee69aSJens Wiklander return db->ops->write(db->fh, idx * l, entry, l); 199*5baee69aSJens Wiklander } 200*5baee69aSJens Wiklander 201*5baee69aSJens Wiklander static TEE_Result tadb_open(struct tee_tadb_dir **db_ret) 202*5baee69aSJens Wiklander { 203*5baee69aSJens Wiklander TEE_Result res; 204*5baee69aSJens Wiklander struct tee_tadb_dir *db = calloc(1, sizeof(*db)); 205*5baee69aSJens Wiklander struct tee_pobj po = { 206*5baee69aSJens Wiklander .obj_id = (void *)tadb_obj_id, 207*5baee69aSJens Wiklander .obj_id_len = sizeof(tadb_obj_id) 208*5baee69aSJens Wiklander }; 209*5baee69aSJens Wiklander 210*5baee69aSJens Wiklander if (!db) 211*5baee69aSJens Wiklander return TEE_ERROR_OUT_OF_MEMORY; 212*5baee69aSJens Wiklander 213*5baee69aSJens Wiklander db->ops = tee_svc_storage_file_ops(TEE_STORAGE_PRIVATE); 214*5baee69aSJens Wiklander 215*5baee69aSJens Wiklander res = db->ops->open(&po, NULL, &db->fh); 216*5baee69aSJens Wiklander if (res == TEE_ERROR_ITEM_NOT_FOUND) 217*5baee69aSJens Wiklander res = db->ops->create(&po, false, NULL, 0, NULL, 0, NULL, 0, 218*5baee69aSJens Wiklander &db->fh); 219*5baee69aSJens Wiklander 220*5baee69aSJens Wiklander if (res) 221*5baee69aSJens Wiklander free(db); 222*5baee69aSJens Wiklander else 223*5baee69aSJens Wiklander *db_ret = db; 224*5baee69aSJens Wiklander 225*5baee69aSJens Wiklander return res; 226*5baee69aSJens Wiklander } 227*5baee69aSJens Wiklander 228*5baee69aSJens Wiklander static TEE_Result tee_tadb_open(struct tee_tadb_dir **db) 229*5baee69aSJens Wiklander { 230*5baee69aSJens Wiklander if (!refcount_inc(&tadb_db_refc)) { 231*5baee69aSJens Wiklander TEE_Result res; 232*5baee69aSJens Wiklander 233*5baee69aSJens Wiklander mutex_lock(&tadb_mutex); 234*5baee69aSJens Wiklander res = tadb_open(&tadb_db); 235*5baee69aSJens Wiklander if (!res) 236*5baee69aSJens Wiklander refcount_set(&tadb_db_refc, 1); 237*5baee69aSJens Wiklander mutex_unlock(&tadb_mutex); 238*5baee69aSJens Wiklander if (res) 239*5baee69aSJens Wiklander return res; 240*5baee69aSJens Wiklander } 241*5baee69aSJens Wiklander 242*5baee69aSJens Wiklander *db = tadb_db; 243*5baee69aSJens Wiklander return TEE_SUCCESS; 244*5baee69aSJens Wiklander } 245*5baee69aSJens Wiklander 246*5baee69aSJens Wiklander static void tadb_put(struct tee_tadb_dir *db) 247*5baee69aSJens Wiklander { 248*5baee69aSJens Wiklander if (refcount_dec(&tadb_db_refc)) { 249*5baee69aSJens Wiklander mutex_lock(&tadb_mutex); 250*5baee69aSJens Wiklander if (!refcount_val(&tadb_db_refc) && tadb_db) { 251*5baee69aSJens Wiklander db->ops->close(&db->fh); 252*5baee69aSJens Wiklander free(db->files); 253*5baee69aSJens Wiklander free(db); 254*5baee69aSJens Wiklander tadb_db = NULL; 255*5baee69aSJens Wiklander } 256*5baee69aSJens Wiklander mutex_unlock(&tadb_mutex); 257*5baee69aSJens Wiklander } 258*5baee69aSJens Wiklander } 259*5baee69aSJens Wiklander 260*5baee69aSJens Wiklander static void tee_tadb_close(struct tee_tadb_dir *db) 261*5baee69aSJens Wiklander { 262*5baee69aSJens Wiklander tadb_put(db); 263*5baee69aSJens Wiklander } 264*5baee69aSJens Wiklander 265*5baee69aSJens Wiklander static TEE_Result tadb_authenc_init(TEE_OperationMode mode, 266*5baee69aSJens Wiklander const struct tadb_entry *entry, 267*5baee69aSJens Wiklander void **ctx_ret) 268*5baee69aSJens Wiklander { 269*5baee69aSJens Wiklander TEE_Result res; 270*5baee69aSJens Wiklander void *ctx; 271*5baee69aSJens Wiklander size_t sz; 272*5baee69aSJens Wiklander const size_t enc_size = entry->prop.custom_size + entry->prop.bin_size; 273*5baee69aSJens Wiklander 274*5baee69aSJens Wiklander res = crypto_authenc_get_ctx_size(TADB_AUTH_ENC_ALG, &sz); 275*5baee69aSJens Wiklander if (res) 276*5baee69aSJens Wiklander return res; 277*5baee69aSJens Wiklander 278*5baee69aSJens Wiklander ctx = malloc(sz); 279*5baee69aSJens Wiklander if (!ctx) 280*5baee69aSJens Wiklander return TEE_ERROR_OUT_OF_MEMORY; 281*5baee69aSJens Wiklander 282*5baee69aSJens Wiklander res = crypto_authenc_init(ctx, TADB_AUTH_ENC_ALG, mode, 283*5baee69aSJens Wiklander entry->key, sizeof(entry->key), 284*5baee69aSJens Wiklander entry->iv, sizeof(entry->iv), 285*5baee69aSJens Wiklander sizeof(entry->tag), 0, enc_size); 286*5baee69aSJens Wiklander if (res) 287*5baee69aSJens Wiklander free(ctx); 288*5baee69aSJens Wiklander else 289*5baee69aSJens Wiklander *ctx_ret = ctx; 290*5baee69aSJens Wiklander 291*5baee69aSJens Wiklander return res; 292*5baee69aSJens Wiklander } 293*5baee69aSJens Wiklander 294*5baee69aSJens Wiklander static TEE_Result tadb_update_payload(void *ctx, TEE_OperationMode mode, 295*5baee69aSJens Wiklander const void *src, size_t len, void *dst) 296*5baee69aSJens Wiklander { 297*5baee69aSJens Wiklander TEE_Result res; 298*5baee69aSJens Wiklander size_t sz = len; 299*5baee69aSJens Wiklander 300*5baee69aSJens Wiklander res = crypto_authenc_update_payload(ctx, TADB_AUTH_ENC_ALG, mode, 301*5baee69aSJens Wiklander (const uint8_t *)src, len, dst, 302*5baee69aSJens Wiklander &sz); 303*5baee69aSJens Wiklander assert(res || sz == len); 304*5baee69aSJens Wiklander return res; 305*5baee69aSJens Wiklander } 306*5baee69aSJens Wiklander 307*5baee69aSJens Wiklander static TEE_Result populate_files(struct tee_tadb_dir *db) 308*5baee69aSJens Wiklander { 309*5baee69aSJens Wiklander TEE_Result res; 310*5baee69aSJens Wiklander size_t idx; 311*5baee69aSJens Wiklander 312*5baee69aSJens Wiklander /* 313*5baee69aSJens Wiklander * If db->files isn't NULL the bitfield is already populated and 314*5baee69aSJens Wiklander * there's nothing left to do here for now. 315*5baee69aSJens Wiklander */ 316*5baee69aSJens Wiklander if (db->files) 317*5baee69aSJens Wiklander return TEE_SUCCESS; 318*5baee69aSJens Wiklander 319*5baee69aSJens Wiklander /* 320*5baee69aSJens Wiklander * Iterate over the TA database and set the bits in the bit field 321*5baee69aSJens Wiklander * for used file numbers. Note that set_file() will allocate and 322*5baee69aSJens Wiklander * grow the bitfield as needed. 323*5baee69aSJens Wiklander * 324*5baee69aSJens Wiklander * At the same time clean out duplicate file numbers, the first 325*5baee69aSJens Wiklander * entry with the file number has precedence. Duplicate entries is 326*5baee69aSJens Wiklander * not supposed to be able to happen, but if it still does better 327*5baee69aSJens Wiklander * to clean it out here instead of letting the error spread with 328*5baee69aSJens Wiklander * unexpected side effects. 329*5baee69aSJens Wiklander */ 330*5baee69aSJens Wiklander for (idx = 0;; idx++) { 331*5baee69aSJens Wiklander struct tadb_entry entry; 332*5baee69aSJens Wiklander 333*5baee69aSJens Wiklander res = read_ent(db, idx, &entry); 334*5baee69aSJens Wiklander if (res) { 335*5baee69aSJens Wiklander if (res == TEE_ERROR_ITEM_NOT_FOUND) 336*5baee69aSJens Wiklander return TEE_SUCCESS; 337*5baee69aSJens Wiklander goto err; 338*5baee69aSJens Wiklander } 339*5baee69aSJens Wiklander 340*5baee69aSJens Wiklander if (is_null_uuid(&entry.prop.uuid)) 341*5baee69aSJens Wiklander continue; 342*5baee69aSJens Wiklander 343*5baee69aSJens Wiklander if (test_file(db, entry.file_number)) { 344*5baee69aSJens Wiklander IMSG("Clearing duplicate file number %" PRIu32, 345*5baee69aSJens Wiklander entry.file_number); 346*5baee69aSJens Wiklander memset(&entry, 0, sizeof(entry)); 347*5baee69aSJens Wiklander res = write_ent(db, idx, &entry); 348*5baee69aSJens Wiklander if (res) 349*5baee69aSJens Wiklander goto err; 350*5baee69aSJens Wiklander continue; 351*5baee69aSJens Wiklander } 352*5baee69aSJens Wiklander 353*5baee69aSJens Wiklander res = set_file(db, entry.file_number); 354*5baee69aSJens Wiklander if (res) 355*5baee69aSJens Wiklander goto err; 356*5baee69aSJens Wiklander } 357*5baee69aSJens Wiklander 358*5baee69aSJens Wiklander err: 359*5baee69aSJens Wiklander free(db->files); 360*5baee69aSJens Wiklander db->files = NULL; 361*5baee69aSJens Wiklander db->nbits = 0; 362*5baee69aSJens Wiklander 363*5baee69aSJens Wiklander return res; 364*5baee69aSJens Wiklander } 365*5baee69aSJens Wiklander 366*5baee69aSJens Wiklander TEE_Result tee_tadb_ta_create(const struct tee_tadb_property *property, 367*5baee69aSJens Wiklander struct tee_tadb_ta_write **ta_ret) 368*5baee69aSJens Wiklander { 369*5baee69aSJens Wiklander TEE_Result res; 370*5baee69aSJens Wiklander struct tee_tadb_ta_write *ta; 371*5baee69aSJens Wiklander int i = 0; 372*5baee69aSJens Wiklander 373*5baee69aSJens Wiklander if (is_null_uuid(&property->uuid)) 374*5baee69aSJens Wiklander return TEE_ERROR_GENERIC; 375*5baee69aSJens Wiklander 376*5baee69aSJens Wiklander ta = calloc(1, sizeof(*ta)); 377*5baee69aSJens Wiklander if (!ta) 378*5baee69aSJens Wiklander return TEE_ERROR_OUT_OF_MEMORY; 379*5baee69aSJens Wiklander 380*5baee69aSJens Wiklander res = tee_tadb_open(&ta->db); 381*5baee69aSJens Wiklander if (res) 382*5baee69aSJens Wiklander goto err; 383*5baee69aSJens Wiklander 384*5baee69aSJens Wiklander mutex_lock(&tadb_mutex); 385*5baee69aSJens Wiklander 386*5baee69aSJens Wiklander /* 387*5baee69aSJens Wiklander * Since we're going to search for next free file number below we 388*5baee69aSJens Wiklander * need to populate the bitfield holding used file numbers. 389*5baee69aSJens Wiklander */ 390*5baee69aSJens Wiklander res = populate_files(ta->db); 391*5baee69aSJens Wiklander if (res) 392*5baee69aSJens Wiklander goto err_mutex; 393*5baee69aSJens Wiklander 394*5baee69aSJens Wiklander if (ta->db->files) { 395*5baee69aSJens Wiklander bit_ffc(ta->db->files, ta->db->nbits, &i); 396*5baee69aSJens Wiklander if (i == -1) 397*5baee69aSJens Wiklander i = ta->db->nbits; 398*5baee69aSJens Wiklander } 399*5baee69aSJens Wiklander 400*5baee69aSJens Wiklander res = set_file(ta->db, i); 401*5baee69aSJens Wiklander if (res) 402*5baee69aSJens Wiklander goto err_mutex; 403*5baee69aSJens Wiklander 404*5baee69aSJens Wiklander mutex_unlock(&tadb_mutex); 405*5baee69aSJens Wiklander 406*5baee69aSJens Wiklander ta->entry.file_number = i; 407*5baee69aSJens Wiklander ta->entry.prop = *property; 408*5baee69aSJens Wiklander 409*5baee69aSJens Wiklander res = crypto_rng_read(ta->entry.iv, sizeof(ta->entry.iv)); 410*5baee69aSJens Wiklander if (res) 411*5baee69aSJens Wiklander goto err; 412*5baee69aSJens Wiklander 413*5baee69aSJens Wiklander res = crypto_rng_read(ta->entry.key, sizeof(ta->entry.key)); 414*5baee69aSJens Wiklander if (res) 415*5baee69aSJens Wiklander goto err; 416*5baee69aSJens Wiklander 417*5baee69aSJens Wiklander res = ta_operation_open(OPTEE_MRF_CREATE, ta->entry.file_number, 418*5baee69aSJens Wiklander &ta->fd); 419*5baee69aSJens Wiklander if (res) 420*5baee69aSJens Wiklander goto err; 421*5baee69aSJens Wiklander 422*5baee69aSJens Wiklander res = tadb_authenc_init(TEE_MODE_ENCRYPT, &ta->entry, &ta->ctx); 423*5baee69aSJens Wiklander if (res) 424*5baee69aSJens Wiklander goto err; 425*5baee69aSJens Wiklander 426*5baee69aSJens Wiklander *ta_ret = ta; 427*5baee69aSJens Wiklander 428*5baee69aSJens Wiklander return TEE_SUCCESS; 429*5baee69aSJens Wiklander 430*5baee69aSJens Wiklander err_mutex: 431*5baee69aSJens Wiklander mutex_unlock(&tadb_mutex); 432*5baee69aSJens Wiklander err: 433*5baee69aSJens Wiklander tadb_put(ta->db); 434*5baee69aSJens Wiklander free(ta); 435*5baee69aSJens Wiklander 436*5baee69aSJens Wiklander return res; 437*5baee69aSJens Wiklander } 438*5baee69aSJens Wiklander 439*5baee69aSJens Wiklander TEE_Result tee_tadb_ta_write(struct tee_tadb_ta_write *ta, const void *buf, 440*5baee69aSJens Wiklander size_t len) 441*5baee69aSJens Wiklander { 442*5baee69aSJens Wiklander TEE_Result res; 443*5baee69aSJens Wiklander const uint8_t *rb = buf; 444*5baee69aSJens Wiklander size_t rl = len; 445*5baee69aSJens Wiklander struct tee_fs_rpc_operation op; 446*5baee69aSJens Wiklander 447*5baee69aSJens Wiklander while (rl) { 448*5baee69aSJens Wiklander size_t wl = MIN(rl, TADB_MAX_BUFFER_SIZE); 449*5baee69aSJens Wiklander void *wb; 450*5baee69aSJens Wiklander 451*5baee69aSJens Wiklander res = tee_fs_rpc_write_init(&op, OPTEE_MSG_RPC_CMD_FS, ta->fd, 452*5baee69aSJens Wiklander ta->pos, wl, &wb); 453*5baee69aSJens Wiklander if (res) 454*5baee69aSJens Wiklander return res; 455*5baee69aSJens Wiklander 456*5baee69aSJens Wiklander res = tadb_update_payload(ta->ctx, TEE_MODE_ENCRYPT, 457*5baee69aSJens Wiklander rb, wl, wb); 458*5baee69aSJens Wiklander if (res) 459*5baee69aSJens Wiklander return res; 460*5baee69aSJens Wiklander 461*5baee69aSJens Wiklander res = tee_fs_rpc_write_final(&op); 462*5baee69aSJens Wiklander if (res) 463*5baee69aSJens Wiklander return res; 464*5baee69aSJens Wiklander 465*5baee69aSJens Wiklander rl -= wl; 466*5baee69aSJens Wiklander rb += wl; 467*5baee69aSJens Wiklander ta->pos += wl; 468*5baee69aSJens Wiklander } 469*5baee69aSJens Wiklander 470*5baee69aSJens Wiklander return TEE_SUCCESS; 471*5baee69aSJens Wiklander } 472*5baee69aSJens Wiklander 473*5baee69aSJens Wiklander void tee_tadb_ta_close_and_delete(struct tee_tadb_ta_write *ta) 474*5baee69aSJens Wiklander { 475*5baee69aSJens Wiklander crypto_authenc_final(ta->ctx, TADB_AUTH_ENC_ALG); 476*5baee69aSJens Wiklander free(ta->ctx); 477*5baee69aSJens Wiklander tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, ta->fd); 478*5baee69aSJens Wiklander ta_operation_remove(ta->entry.file_number); 479*5baee69aSJens Wiklander 480*5baee69aSJens Wiklander mutex_lock(&tadb_mutex); 481*5baee69aSJens Wiklander clear_file(ta->db, ta->entry.file_number); 482*5baee69aSJens Wiklander mutex_unlock(&tadb_mutex); 483*5baee69aSJens Wiklander 484*5baee69aSJens Wiklander tadb_put(ta->db); 485*5baee69aSJens Wiklander free(ta); 486*5baee69aSJens Wiklander } 487*5baee69aSJens Wiklander 488*5baee69aSJens Wiklander static TEE_Result find_ent(struct tee_tadb_dir *db, const TEE_UUID *uuid, 489*5baee69aSJens Wiklander size_t *idx_ret, struct tadb_entry *entry_ret) 490*5baee69aSJens Wiklander { 491*5baee69aSJens Wiklander TEE_Result res; 492*5baee69aSJens Wiklander size_t idx; 493*5baee69aSJens Wiklander 494*5baee69aSJens Wiklander /* 495*5baee69aSJens Wiklander * Search for the provided uuid, if it's found return the index it 496*5baee69aSJens Wiklander * has together with TEE_SUCCESS. 497*5baee69aSJens Wiklander * 498*5baee69aSJens Wiklander * If the uuid can't be found return the number indexes together 499*5baee69aSJens Wiklander * with TEE_ERROR_ITEM_NOT_FOUND. 500*5baee69aSJens Wiklander */ 501*5baee69aSJens Wiklander for (idx = 0;; idx++) { 502*5baee69aSJens Wiklander struct tadb_entry entry; 503*5baee69aSJens Wiklander 504*5baee69aSJens Wiklander res = read_ent(db, idx, &entry); 505*5baee69aSJens Wiklander if (res) { 506*5baee69aSJens Wiklander if (res == TEE_ERROR_ITEM_NOT_FOUND) 507*5baee69aSJens Wiklander break; 508*5baee69aSJens Wiklander return res; 509*5baee69aSJens Wiklander } 510*5baee69aSJens Wiklander 511*5baee69aSJens Wiklander if (!memcmp(&entry.prop.uuid, uuid, sizeof(*uuid))) { 512*5baee69aSJens Wiklander if (entry_ret) 513*5baee69aSJens Wiklander *entry_ret = entry; 514*5baee69aSJens Wiklander break; 515*5baee69aSJens Wiklander } 516*5baee69aSJens Wiklander } 517*5baee69aSJens Wiklander 518*5baee69aSJens Wiklander *idx_ret = idx; 519*5baee69aSJens Wiklander return res; 520*5baee69aSJens Wiklander } 521*5baee69aSJens Wiklander 522*5baee69aSJens Wiklander static TEE_Result find_free_ent_idx(struct tee_tadb_dir *db, size_t *idx) 523*5baee69aSJens Wiklander { 524*5baee69aSJens Wiklander const TEE_UUID null_uuid = { 0 }; 525*5baee69aSJens Wiklander TEE_Result res = find_ent(db, &null_uuid, idx, NULL); 526*5baee69aSJens Wiklander 527*5baee69aSJens Wiklander /* 528*5baee69aSJens Wiklander * Note that *idx is set to the number of entries on 529*5baee69aSJens Wiklander * TEE_ERROR_ITEM_NOT_FOUND. 530*5baee69aSJens Wiklander */ 531*5baee69aSJens Wiklander if (res == TEE_ERROR_ITEM_NOT_FOUND) 532*5baee69aSJens Wiklander return TEE_SUCCESS; 533*5baee69aSJens Wiklander return res; 534*5baee69aSJens Wiklander } 535*5baee69aSJens Wiklander 536*5baee69aSJens Wiklander TEE_Result tee_tadb_ta_close_and_commit(struct tee_tadb_ta_write *ta) 537*5baee69aSJens Wiklander { 538*5baee69aSJens Wiklander TEE_Result res; 539*5baee69aSJens Wiklander size_t dsz = 0; 540*5baee69aSJens Wiklander size_t sz = sizeof(ta->entry.tag); 541*5baee69aSJens Wiklander size_t idx; 542*5baee69aSJens Wiklander struct tadb_entry old_ent; 543*5baee69aSJens Wiklander bool have_old_ent = false; 544*5baee69aSJens Wiklander 545*5baee69aSJens Wiklander res = crypto_authenc_enc_final(ta->ctx, TADB_AUTH_ENC_ALG, 546*5baee69aSJens Wiklander NULL, 0, NULL, &dsz, 547*5baee69aSJens Wiklander ta->entry.tag, &sz); 548*5baee69aSJens Wiklander if (res) 549*5baee69aSJens Wiklander goto err; 550*5baee69aSJens Wiklander 551*5baee69aSJens Wiklander tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, ta->fd); 552*5baee69aSJens Wiklander 553*5baee69aSJens Wiklander mutex_lock(&tadb_mutex); 554*5baee69aSJens Wiklander /* 555*5baee69aSJens Wiklander * First try to find an existing TA to replace. If there's one 556*5baee69aSJens Wiklander * we'll use the entry, but we should also remove the old encrypted 557*5baee69aSJens Wiklander * file. 558*5baee69aSJens Wiklander * 559*5baee69aSJens Wiklander * If there isn't an existing TA to replace, grab a new entry. 560*5baee69aSJens Wiklander */ 561*5baee69aSJens Wiklander res = find_ent(ta->db, &ta->entry.prop.uuid, &idx, &old_ent); 562*5baee69aSJens Wiklander if (!res) { 563*5baee69aSJens Wiklander have_old_ent = true; 564*5baee69aSJens Wiklander } else { 565*5baee69aSJens Wiklander res = find_free_ent_idx(ta->db, &idx); 566*5baee69aSJens Wiklander if (res) 567*5baee69aSJens Wiklander goto err_mutex; 568*5baee69aSJens Wiklander } 569*5baee69aSJens Wiklander res = write_ent(ta->db, idx, &ta->entry); 570*5baee69aSJens Wiklander if (res) 571*5baee69aSJens Wiklander goto err_mutex; 572*5baee69aSJens Wiklander if (have_old_ent) 573*5baee69aSJens Wiklander clear_file(ta->db, old_ent.file_number); 574*5baee69aSJens Wiklander mutex_unlock(&tadb_mutex); 575*5baee69aSJens Wiklander 576*5baee69aSJens Wiklander crypto_authenc_final(ta->ctx, TADB_AUTH_ENC_ALG); 577*5baee69aSJens Wiklander free(ta->ctx); 578*5baee69aSJens Wiklander tadb_put(ta->db); 579*5baee69aSJens Wiklander free(ta); 580*5baee69aSJens Wiklander if (have_old_ent) 581*5baee69aSJens Wiklander ta_operation_remove(old_ent.file_number); 582*5baee69aSJens Wiklander return TEE_SUCCESS; 583*5baee69aSJens Wiklander 584*5baee69aSJens Wiklander err_mutex: 585*5baee69aSJens Wiklander mutex_unlock(&tadb_mutex); 586*5baee69aSJens Wiklander err: 587*5baee69aSJens Wiklander tee_tadb_ta_close_and_delete(ta); 588*5baee69aSJens Wiklander return res; 589*5baee69aSJens Wiklander } 590*5baee69aSJens Wiklander 591*5baee69aSJens Wiklander TEE_Result tee_tadb_ta_delete(const TEE_UUID *uuid) 592*5baee69aSJens Wiklander { 593*5baee69aSJens Wiklander const struct tadb_entry null_entry = { 0 }; 594*5baee69aSJens Wiklander struct tee_tadb_dir *db; 595*5baee69aSJens Wiklander struct tadb_entry entry; 596*5baee69aSJens Wiklander size_t idx; 597*5baee69aSJens Wiklander TEE_Result res; 598*5baee69aSJens Wiklander 599*5baee69aSJens Wiklander if (is_null_uuid(uuid)) 600*5baee69aSJens Wiklander return TEE_ERROR_GENERIC; 601*5baee69aSJens Wiklander 602*5baee69aSJens Wiklander res = tee_tadb_open(&db); 603*5baee69aSJens Wiklander if (res) 604*5baee69aSJens Wiklander return res; 605*5baee69aSJens Wiklander 606*5baee69aSJens Wiklander mutex_lock(&tadb_mutex); 607*5baee69aSJens Wiklander res = find_ent(db, uuid, &idx, &entry); 608*5baee69aSJens Wiklander if (res) { 609*5baee69aSJens Wiklander mutex_unlock(&tadb_mutex); 610*5baee69aSJens Wiklander tee_tadb_close(db); 611*5baee69aSJens Wiklander return res; 612*5baee69aSJens Wiklander } 613*5baee69aSJens Wiklander 614*5baee69aSJens Wiklander clear_file(db, entry.file_number); 615*5baee69aSJens Wiklander res = write_ent(db, idx, &null_entry); 616*5baee69aSJens Wiklander mutex_unlock(&tadb_mutex); 617*5baee69aSJens Wiklander 618*5baee69aSJens Wiklander tee_tadb_close(db); 619*5baee69aSJens Wiklander if (res) 620*5baee69aSJens Wiklander return res; 621*5baee69aSJens Wiklander 622*5baee69aSJens Wiklander ta_operation_remove(entry.file_number); 623*5baee69aSJens Wiklander return TEE_SUCCESS; 624*5baee69aSJens Wiklander } 625*5baee69aSJens Wiklander 626*5baee69aSJens Wiklander TEE_Result tee_tadb_ta_open(const TEE_UUID *uuid, 627*5baee69aSJens Wiklander struct tee_tadb_ta_read **ta_ret) 628*5baee69aSJens Wiklander { 629*5baee69aSJens Wiklander TEE_Result res; 630*5baee69aSJens Wiklander size_t idx; 631*5baee69aSJens Wiklander struct tee_tadb_ta_read *ta; 632*5baee69aSJens Wiklander static struct tadb_entry last_entry; 633*5baee69aSJens Wiklander 634*5baee69aSJens Wiklander if (is_null_uuid(uuid)) 635*5baee69aSJens Wiklander return TEE_ERROR_GENERIC; 636*5baee69aSJens Wiklander 637*5baee69aSJens Wiklander ta = calloc(1, sizeof(*ta)); 638*5baee69aSJens Wiklander if (!ta) 639*5baee69aSJens Wiklander return TEE_ERROR_OUT_OF_MEMORY; 640*5baee69aSJens Wiklander 641*5baee69aSJens Wiklander if (!memcmp(uuid, &last_entry.prop.uuid, sizeof(*uuid))) { 642*5baee69aSJens Wiklander ta->entry = last_entry; 643*5baee69aSJens Wiklander } else { 644*5baee69aSJens Wiklander res = tee_tadb_open(&ta->db); 645*5baee69aSJens Wiklander if (res) 646*5baee69aSJens Wiklander goto err_free; /* Mustn't all tadb_put() */ 647*5baee69aSJens Wiklander 648*5baee69aSJens Wiklander mutex_read_lock(&tadb_mutex); 649*5baee69aSJens Wiklander res = find_ent(ta->db, uuid, &idx, &ta->entry); 650*5baee69aSJens Wiklander mutex_read_unlock(&tadb_mutex); 651*5baee69aSJens Wiklander if (res) 652*5baee69aSJens Wiklander goto err; 653*5baee69aSJens Wiklander } 654*5baee69aSJens Wiklander 655*5baee69aSJens Wiklander res = ta_operation_open(OPTEE_MRF_OPEN, ta->entry.file_number, &ta->fd); 656*5baee69aSJens Wiklander if (res) 657*5baee69aSJens Wiklander goto err; 658*5baee69aSJens Wiklander 659*5baee69aSJens Wiklander res = tadb_authenc_init(TEE_MODE_DECRYPT, &ta->entry, &ta->ctx); 660*5baee69aSJens Wiklander if (res) 661*5baee69aSJens Wiklander goto err; 662*5baee69aSJens Wiklander 663*5baee69aSJens Wiklander *ta_ret = ta; 664*5baee69aSJens Wiklander 665*5baee69aSJens Wiklander return TEE_SUCCESS; 666*5baee69aSJens Wiklander err: 667*5baee69aSJens Wiklander tadb_put(ta->db); 668*5baee69aSJens Wiklander err_free: 669*5baee69aSJens Wiklander free(ta); 670*5baee69aSJens Wiklander return res; 671*5baee69aSJens Wiklander } 672*5baee69aSJens Wiklander 673*5baee69aSJens Wiklander const struct tee_tadb_property * 674*5baee69aSJens Wiklander tee_tadb_ta_get_property(struct tee_tadb_ta_read *ta) 675*5baee69aSJens Wiklander { 676*5baee69aSJens Wiklander return &ta->entry.prop; 677*5baee69aSJens Wiklander } 678*5baee69aSJens Wiklander 679*5baee69aSJens Wiklander static TEE_Result ta_load(struct tee_tadb_ta_read *ta) 680*5baee69aSJens Wiklander { 681*5baee69aSJens Wiklander TEE_Result res; 682*5baee69aSJens Wiklander const size_t sz = ta->entry.prop.custom_size + ta->entry.prop.bin_size; 683*5baee69aSJens Wiklander struct optee_msg_param params[2] = { 684*5baee69aSJens Wiklander [0] = { .attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT, 685*5baee69aSJens Wiklander .u.value.a = OPTEE_MRF_READ, 686*5baee69aSJens Wiklander .u.value.b = ta->fd, 687*5baee69aSJens Wiklander .u.value.c = 0 }, 688*5baee69aSJens Wiklander }; 689*5baee69aSJens Wiklander 690*5baee69aSJens Wiklander if (ta->ta_mobj) 691*5baee69aSJens Wiklander return TEE_SUCCESS; 692*5baee69aSJens Wiklander 693*5baee69aSJens Wiklander ta->ta_mobj = thread_rpc_alloc_payload(sz, &ta->ta_cookie); 694*5baee69aSJens Wiklander if (!ta->ta_mobj) 695*5baee69aSJens Wiklander return TEE_ERROR_OUT_OF_MEMORY; 696*5baee69aSJens Wiklander 697*5baee69aSJens Wiklander ta->ta_buf = mobj_get_va(ta->ta_mobj, 0); 698*5baee69aSJens Wiklander assert(ta->ta_buf); 699*5baee69aSJens Wiklander 700*5baee69aSJens Wiklander if (!msg_param_init_memparam(params + 1, ta->ta_mobj, 0, sz, 701*5baee69aSJens Wiklander ta->ta_cookie, MSG_PARAM_MEM_DIR_OUT)) 702*5baee69aSJens Wiklander return TEE_ERROR_BAD_STATE; 703*5baee69aSJens Wiklander 704*5baee69aSJens Wiklander res = thread_rpc_cmd(OPTEE_MSG_RPC_CMD_FS, ARRAY_SIZE(params), params); 705*5baee69aSJens Wiklander if (res) { 706*5baee69aSJens Wiklander thread_rpc_free_payload(ta->ta_cookie, ta->ta_mobj); 707*5baee69aSJens Wiklander ta->ta_mobj = NULL; 708*5baee69aSJens Wiklander } 709*5baee69aSJens Wiklander return res; 710*5baee69aSJens Wiklander } 711*5baee69aSJens Wiklander 712*5baee69aSJens Wiklander TEE_Result tee_tadb_ta_read(struct tee_tadb_ta_read *ta, void *buf, size_t *len) 713*5baee69aSJens Wiklander { 714*5baee69aSJens Wiklander TEE_Result res; 715*5baee69aSJens Wiklander const size_t sz = ta->entry.prop.custom_size + ta->entry.prop.bin_size; 716*5baee69aSJens Wiklander size_t l = MIN(*len, sz - ta->pos); 717*5baee69aSJens Wiklander 718*5baee69aSJens Wiklander res = ta_load(ta); 719*5baee69aSJens Wiklander if (res) 720*5baee69aSJens Wiklander return res; 721*5baee69aSJens Wiklander 722*5baee69aSJens Wiklander if (buf) { 723*5baee69aSJens Wiklander res = tadb_update_payload(ta->ctx, TEE_MODE_DECRYPT, 724*5baee69aSJens Wiklander ta->ta_buf + ta->pos, l, buf); 725*5baee69aSJens Wiklander if (res) 726*5baee69aSJens Wiklander return res; 727*5baee69aSJens Wiklander } else { 728*5baee69aSJens Wiklander size_t num_bytes = 0; 729*5baee69aSJens Wiklander size_t b_size = MIN(SIZE_4K, l); 730*5baee69aSJens Wiklander uint8_t *b = malloc(b_size); 731*5baee69aSJens Wiklander 732*5baee69aSJens Wiklander if (!b) 733*5baee69aSJens Wiklander return TEE_ERROR_OUT_OF_MEMORY; 734*5baee69aSJens Wiklander 735*5baee69aSJens Wiklander while (num_bytes < l) { 736*5baee69aSJens Wiklander size_t n = MIN(b_size, l - num_bytes); 737*5baee69aSJens Wiklander 738*5baee69aSJens Wiklander res = tadb_update_payload(ta->ctx, TEE_MODE_DECRYPT, 739*5baee69aSJens Wiklander ta->ta_buf + ta->pos, n, b); 740*5baee69aSJens Wiklander if (res) 741*5baee69aSJens Wiklander break; 742*5baee69aSJens Wiklander num_bytes += n; 743*5baee69aSJens Wiklander } 744*5baee69aSJens Wiklander 745*5baee69aSJens Wiklander free(b); 746*5baee69aSJens Wiklander if (res) 747*5baee69aSJens Wiklander return res; 748*5baee69aSJens Wiklander } 749*5baee69aSJens Wiklander 750*5baee69aSJens Wiklander ta->pos += l; 751*5baee69aSJens Wiklander *len = l; 752*5baee69aSJens Wiklander return TEE_SUCCESS; 753*5baee69aSJens Wiklander } 754*5baee69aSJens Wiklander 755*5baee69aSJens Wiklander void tee_tadb_ta_close(struct tee_tadb_ta_read *ta) 756*5baee69aSJens Wiklander { 757*5baee69aSJens Wiklander crypto_authenc_final(ta->ctx, TADB_AUTH_ENC_ALG); 758*5baee69aSJens Wiklander free(ta->ctx); 759*5baee69aSJens Wiklander if (ta->ta_mobj) 760*5baee69aSJens Wiklander thread_rpc_free_payload(ta->ta_cookie, ta->ta_mobj); 761*5baee69aSJens Wiklander tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, ta->fd); 762*5baee69aSJens Wiklander tadb_put(ta->db); 763*5baee69aSJens Wiklander free(ta); 764*5baee69aSJens Wiklander } 765