From 334316feab7445d4cb040ee11dbbf53d61ad2320 Mon Sep 17 00:00:00 2001 From: Jens Wiklander Date: Mon, 4 May 2020 10:36:43 +0200 Subject: ta: pkcs11: persistent object support A persistent object (token object in PKCS#11 spec) is stored as a binary blob of attribute list identified by a UUID. The persistent database stores the UUIDs of the persistent objects of the token. Reviewed-by: Ricardo Salveti Co-developed-by: Etienne Carriere Signed-off-by: Etienne Carriere Signed-off-by: Jens Wiklander --- ta/pkcs11/src/persistent_token.c | 244 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 243 insertions(+), 1 deletion(-) (limited to 'ta/pkcs11/src/persistent_token.c') diff --git a/ta/pkcs11/src/persistent_token.c b/ta/pkcs11/src/persistent_token.c index af3db4a8..5dc015c3 100644 --- a/ta/pkcs11/src/persistent_token.c +++ b/ta/pkcs11/src/persistent_token.c @@ -17,6 +17,11 @@ /* * Token persistent objects + * + * The persistent objects are each identified by a UUID. + * The persistent object database stores the list of the UUIDs registered. For + * each it is expected that a file of ID "UUID" is stored in the TA secure + * storage. */ static TEE_Result get_db_file_name(struct ck_token *token, char *name, size_t size) @@ -130,6 +135,179 @@ void close_persistent_db(struct ck_token *token __unused) { } +static int get_persistent_obj_idx(struct ck_token *token, TEE_UUID *uuid) +{ + size_t i = 0; + + if (!uuid) + return -1; + + for (i = 0; i < token->db_objs->count; i++) + if (!TEE_MemCompare(token->db_objs->uuids + i, + uuid, sizeof(TEE_UUID))) + return i; + + return -1; +} + +/* UUID for persistent object */ +enum pkcs11_rc create_object_uuid(struct ck_token *token, + struct pkcs11_object *obj) +{ + assert(!obj->uuid); + + obj->uuid = TEE_Malloc(sizeof(TEE_UUID), + TEE_USER_MEM_HINT_NO_FILL_ZERO); + if (!obj->uuid) + return PKCS11_CKR_DEVICE_MEMORY; + + do { + TEE_GenerateRandom(obj->uuid, sizeof(TEE_UUID)); + } while (get_persistent_obj_idx(token, obj->uuid) >= 0); + + return PKCS11_CKR_OK; +} + +void destroy_object_uuid(struct ck_token *token __maybe_unused, + struct pkcs11_object *obj) +{ + assert(get_persistent_obj_idx(token, obj->uuid) < 0); + + TEE_Free(obj->uuid); + obj->uuid = NULL; +} + +enum pkcs11_rc get_persistent_objects_list(struct ck_token *token, + TEE_UUID *array, size_t *size) +{ + size_t out_size = *size; + + *size = token->db_objs->count * sizeof(TEE_UUID); + + if (out_size < *size) + return PKCS11_CKR_BUFFER_TOO_SMALL; + + if (array) + TEE_MemMove(array, token->db_objs->uuids, *size); + + return PKCS11_CKR_OK; +} + +enum pkcs11_rc unregister_persistent_object(struct ck_token *token, + TEE_UUID *uuid) +{ + TEE_ObjectHandle db_hdl = TEE_HANDLE_NULL; + struct token_persistent_objs *ptr = NULL; + TEE_Result res = TEE_ERROR_GENERIC; + int count = 0; + int idx = 0; + + if (!uuid) + return PKCS11_CKR_OK; + + idx = get_persistent_obj_idx(token, uuid); + if (idx < 0) { + DMSG("Cannot unregister an invalid persistent object"); + return PKCS11_RV_NOT_FOUND; + } + + ptr = TEE_Malloc(sizeof(struct token_persistent_objs) + + ((token->db_objs->count - 1) * sizeof(TEE_UUID)), + TEE_USER_MEM_HINT_NO_FILL_ZERO); + if (!ptr) + return PKCS11_CKR_DEVICE_MEMORY; + + res = open_db_file(token, &db_hdl); + if (res) + goto out; + + res = TEE_SeekObjectData(db_hdl, sizeof(struct token_persistent_main), + TEE_DATA_SEEK_SET); + if (res) { + DMSG("Failed to read database"); + goto out; + } + + TEE_MemMove(ptr, token->db_objs, + sizeof(struct token_persistent_objs) + + idx * sizeof(TEE_UUID)); + + ptr->count--; + count = ptr->count - idx; + + TEE_MemMove(&ptr->uuids[idx], + &token->db_objs->uuids[idx + 1], + count * sizeof(TEE_UUID)); + + res = TEE_WriteObjectData(db_hdl, ptr, + sizeof(struct token_persistent_objs) + + ptr->count * sizeof(TEE_UUID)); + if (res) + DMSG("Failed to update database"); + TEE_Free(token->db_objs); + token->db_objs = ptr; + ptr = NULL; + +out: + TEE_CloseObject(db_hdl); + TEE_Free(ptr); + + return tee2pkcs_error(res); +} + +enum pkcs11_rc register_persistent_object(struct ck_token *token, + TEE_UUID *uuid) +{ + TEE_ObjectHandle db_hdl = TEE_HANDLE_NULL; + TEE_Result res = TEE_ERROR_GENERIC; + void *ptr = NULL; + size_t size = 0; + int count = 0; + + if (get_persistent_obj_idx(token, uuid) >= 0) + TEE_Panic(0); + + count = token->db_objs->count; + ptr = TEE_Realloc(token->db_objs, + sizeof(struct token_persistent_objs) + + ((count + 1) * sizeof(TEE_UUID))); + if (!ptr) + return PKCS11_CKR_DEVICE_MEMORY; + + token->db_objs = ptr; + TEE_MemMove(token->db_objs->uuids + count, uuid, sizeof(TEE_UUID)); + + size = sizeof(struct token_persistent_main) + + sizeof(struct token_persistent_objs) + + count * sizeof(TEE_UUID); + + res = open_db_file(token, &db_hdl); + if (res) + goto out; + + res = TEE_TruncateObjectData(db_hdl, size + sizeof(TEE_UUID)); + if (res) + goto out; + + res = TEE_SeekObjectData(db_hdl, sizeof(struct token_persistent_main), + TEE_DATA_SEEK_SET); + if (res) + goto out; + + token->db_objs->count++; + + res = TEE_WriteObjectData(db_hdl, token->db_objs, + sizeof(struct token_persistent_objs) + + token->db_objs->count * sizeof(TEE_UUID)); + if (res) + token->db_objs->count--; + +out: + TEE_CloseObject(db_hdl); + + return tee2pkcs_error(res); +} + /* * Return the token instance, either initialized from reset or initialized * from the token persistent state if found. @@ -141,18 +319,24 @@ struct ck_token *init_persistent_db(unsigned int token_id) TEE_ObjectHandle db_hdl = TEE_HANDLE_NULL; /* Copy persistent database: main db and object db */ struct token_persistent_main *db_main = NULL; + struct token_persistent_objs *db_objs = NULL; + void *ptr = NULL; if (!token) return NULL; + LIST_INIT(&token->object_list); + db_main = TEE_Malloc(sizeof(*db_main), TEE_MALLOC_FILL_ZERO); - if (!db_main) + db_objs = TEE_Malloc(sizeof(*db_objs), TEE_MALLOC_FILL_ZERO); + if (!db_main || !db_objs) goto error; res = open_db_file(token, &db_hdl); if (res == TEE_SUCCESS) { uint32_t size = 0; + size_t idx = 0; IMSG("PKCS11 token %u: load db", token_id); @@ -160,6 +344,42 @@ struct ck_token *init_persistent_db(unsigned int token_id) res = TEE_ReadObjectData(db_hdl, db_main, size, &size); if (res || size != sizeof(*db_main)) TEE_Panic(0); + + size = sizeof(*db_objs); + res = TEE_ReadObjectData(db_hdl, db_objs, size, &size); + if (res || size != sizeof(*db_objs)) + TEE_Panic(0); + + size += db_objs->count * sizeof(TEE_UUID); + ptr = TEE_Realloc(db_objs, size); + if (!ptr) + goto error; + + db_objs = ptr; + size -= sizeof(struct token_persistent_objs); + res = TEE_ReadObjectData(db_hdl, db_objs->uuids, size, &size); + if (res || size != (db_objs->count * sizeof(TEE_UUID))) + TEE_Panic(0); + + for (idx = 0; idx < db_objs->count; idx++) { + /* Create an empty object instance */ + struct pkcs11_object *obj = NULL; + TEE_UUID *uuid = NULL; + + uuid = TEE_Malloc(sizeof(TEE_UUID), + TEE_USER_MEM_HINT_NO_FILL_ZERO); + if (!uuid) + goto error; + + TEE_MemMove(uuid, &db_objs->uuids[idx], sizeof(*uuid)); + + obj = create_token_object(NULL, uuid); + if (!obj) + TEE_Panic(0); + + LIST_INSERT_HEAD(&token->object_list, obj, link); + } + } else if (res == TEE_ERROR_ITEM_NOT_FOUND) { char file[PERSISTENT_OBJECT_ID_LEN] = { }; @@ -178,6 +398,10 @@ struct ck_token *init_persistent_db(unsigned int token_id) if (res) TEE_Panic(0); + /* + * Object stores persistent state + persistent object + * references. + */ res = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE, file, sizeof(file), TEE_DATA_FLAG_ACCESS_READ | @@ -189,17 +413,35 @@ struct ck_token *init_persistent_db(unsigned int token_id) EMSG("Failed to create db: %"PRIx32, res); goto error; } + + res = TEE_TruncateObjectData(db_hdl, sizeof(*db_main) + + sizeof(*db_objs)); + if (res) + TEE_Panic(0); + + res = TEE_SeekObjectData(db_hdl, sizeof(*db_main), + TEE_DATA_SEEK_SET); + if (res) + TEE_Panic(0); + + db_objs->count = 0; + res = TEE_WriteObjectData(db_hdl, db_objs, sizeof(*db_objs)); + if (res) + TEE_Panic(0); + } else { goto error; } token->db_main = db_main; + token->db_objs = db_objs; TEE_CloseObject(db_hdl); return token; error: TEE_Free(db_main); + TEE_Free(db_objs); if (db_hdl != TEE_HANDLE_NULL) TEE_CloseObject(db_hdl); -- cgit v1.2.3