summaryrefslogtreecommitdiff
path: root/ta/pkcs11/src/persistent_token.c
diff options
context:
space:
mode:
authorJens Wiklander <jens.wiklander@linaro.org>2020-05-04 10:36:43 +0200
committerJérôme Forissier <jerome@forissier.org>2020-07-14 18:42:38 +0200
commit334316feab7445d4cb040ee11dbbf53d61ad2320 (patch)
tree3f2f884d0ba5706feaed436bf4cdf59cf5d15542 /ta/pkcs11/src/persistent_token.c
parentb56b3d071d79537f0b9c86d26c033d9ed5c0206a (diff)
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 <ricardo@foundries.io> Co-developed-by: Etienne Carriere <etienne.carriere@linaro.org> Signed-off-by: Etienne Carriere <etienne.carriere@linaro.org> Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
Diffstat (limited to 'ta/pkcs11/src/persistent_token.c')
-rw-r--r--ta/pkcs11/src/persistent_token.c244
1 files changed, 243 insertions, 1 deletions
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);