diff options
author | Jens Wiklander <jens.wiklander@linaro.org> | 2020-05-04 10:37:47 +0200 |
---|---|---|
committer | Jérôme Forissier <jerome@forissier.org> | 2020-07-14 18:42:38 +0200 |
commit | b56b3d071d79537f0b9c86d26c033d9ed5c0206a (patch) | |
tree | c8cb8fc35214421ac7380943e6e3357ddc2ada15 | |
parent | 63f89caa9022ecf51d1b82dc78af35ba9e38466d (diff) |
ta: pkcs11: support command to import and destroy object
Implement commands PKCS11_CMD_CREATE_OBJECT and PKCS11_CMD_DESTROY_OBJECT.
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>
-rw-r--r-- | ta/pkcs11/src/entry.c | 8 | ||||
-rw-r--r-- | ta/pkcs11/src/object.c | 340 | ||||
-rw-r--r-- | ta/pkcs11/src/object.h | 59 | ||||
-rw-r--r-- | ta/pkcs11/src/pkcs11_token.c | 9 | ||||
-rw-r--r-- | ta/pkcs11/src/pkcs11_token.h | 14 | ||||
-rw-r--r-- | ta/pkcs11/src/sub.mk | 1 |
6 files changed, 431 insertions, 0 deletions
diff --git a/ta/pkcs11/src/entry.c b/ta/pkcs11/src/entry.c index ece7f74d..efce5c62 100644 --- a/ta/pkcs11/src/entry.c +++ b/ta/pkcs11/src/entry.c @@ -10,6 +10,7 @@ #include <tee_internal_api_extensions.h> #include <util.h> +#include "object.h" #include "pkcs11_helpers.h" #include "pkcs11_token.h" @@ -200,6 +201,13 @@ TEE_Result TA_InvokeCommandEntryPoint(void *tee_session, uint32_t cmd, rc = entry_ck_logout(client, ptypes, params); break; + case PKCS11_CMD_CREATE_OBJECT: + rc = entry_create_object(client, ptypes, params); + break; + case PKCS11_CMD_DESTROY_OBJECT: + rc = entry_destroy_object(client, ptypes, params); + break; + default: EMSG("Command %#"PRIx32" is not supported", cmd); return TEE_ERROR_NOT_SUPPORTED; diff --git a/ta/pkcs11/src/object.c b/ta/pkcs11/src/object.c new file mode 100644 index 00000000..48253487 --- /dev/null +++ b/ta/pkcs11/src/object.c @@ -0,0 +1,340 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2017-2020, Linaro Limited + */ + +#include <assert.h> +#include <inttypes.h> +#include <string_ext.h> +#include <tee_internal_api.h> +#include <tee_internal_api_extensions.h> + +#include "attributes.h" +#include "handle.h" +#include "object.h" +#include "pkcs11_attributes.h" +#include "pkcs11_helpers.h" +#include "pkcs11_token.h" +#include "sanitize_object.h" +#include "serializer.h" + +struct pkcs11_object *pkcs11_handle2object(uint32_t handle, + struct pkcs11_session *session) +{ + return handle_lookup(&session->object_handle_db, handle); +} + +uint32_t pkcs11_object2handle(struct pkcs11_object *obj, + struct pkcs11_session *session) +{ + return handle_lookup_handle(&session->object_handle_db, obj); +} + +/* Currently handle pkcs11 sessions and tokens */ + +static struct object_list *get_session_objects(void *session) +{ + /* Currently supporting only pkcs11 session */ + struct pkcs11_session *ck_session = session; + + return pkcs11_get_session_objects(ck_session); +} + +/* Release resources of a non-persistent object */ +static void cleanup_volatile_obj_ref(struct pkcs11_object *obj) +{ + if (!obj) + return; + + if (obj->key_handle != TEE_HANDLE_NULL) + TEE_FreeTransientObject(obj->key_handle); + + if (obj->attribs_hdl != TEE_HANDLE_NULL) + TEE_CloseObject(obj->attribs_hdl); + + TEE_Free(obj->attributes); + TEE_Free(obj->uuid); + TEE_Free(obj); +} + +/* Release resources of a persistent object including volatile resources */ +static void cleanup_persistent_object(struct pkcs11_object *obj __unused, + struct ck_token *token __unused) +{ + EMSG("Persistent object not yet supported, panic!"); + TEE_Panic(0); +} + +/* + * destroy_object - destroy an PKCS11 TA object + * + * @session - session requesting object destruction + * @obj - reference to the PKCS11 TA object + * @session_only - true if only session object shall be destroyed + */ +void destroy_object(struct pkcs11_session *session, struct pkcs11_object *obj, + bool session_only) +{ +#ifdef DEBUG + trace_attributes("[destroy]", obj->attributes); + if (obj->uuid) + MSG_RAW("[destroy] obj uuid %pUl", (void *)obj->uuid); +#endif + + /* + * Remove from session list only if it was published. + * + * This depends on obj->link.le_prev always pointing on the + * link.le_next element in the previous object in the list even if + * there's only a single object in the list. In the first object in + * the list obj->link.le_prev instead points to lh_first in the + * list head. If list implementation is changed we need to revisit + * this. + */ + if (obj->link.le_next || obj->link.le_prev) + LIST_REMOVE(obj, link); + + if (session_only) { + /* Destroy object due to session closure */ + handle_put(&session->object_handle_db, + pkcs11_object2handle(obj, session)); + cleanup_volatile_obj_ref(obj); + + return; + } + + /* Destroy target object (persistent or not) */ + if (get_bool(obj->attributes, PKCS11_CKA_TOKEN)) { + EMSG("Persistent object not yet supported, panic!"); + TEE_Panic(0); + } else { + handle_put(&session->object_handle_db, + pkcs11_object2handle(obj, session)); + cleanup_volatile_obj_ref(obj); + } +} + +static struct pkcs11_object *create_obj_instance(struct obj_attrs *head) +{ + struct pkcs11_object *obj = NULL; + + obj = TEE_Malloc(sizeof(struct pkcs11_object), TEE_MALLOC_FILL_ZERO); + if (!obj) + return NULL; + + obj->key_handle = TEE_HANDLE_NULL; + obj->attribs_hdl = TEE_HANDLE_NULL; + obj->attributes = head; + + return obj; +} + +/* + * create_object - create an PKCS11 TA object from its attributes and value + * + * @sess - session requesting object creation + * @head - reference to serialized attributes + * @out_handle - generated handle for the created object + */ +enum pkcs11_rc create_object(void *sess, struct obj_attrs *head, + uint32_t *out_handle) +{ + enum pkcs11_rc rc = 0; + struct pkcs11_object *obj = NULL; + struct pkcs11_session *session = (struct pkcs11_session *)sess; + uint32_t obj_handle = 0; + +#ifdef DEBUG + trace_attributes("[create]", head); +#endif + + /* + * We do not check the key attributes. At this point, key attributes + * are expected consistent and reliable. + */ + + obj = create_obj_instance(head); + if (!obj) + return PKCS11_CKR_DEVICE_MEMORY; + + /* Create a handle for the object in the session database */ + obj_handle = handle_get(&session->object_handle_db, obj); + if (!obj_handle) { + rc = PKCS11_CKR_DEVICE_MEMORY; + goto err; + } + + if (get_bool(obj->attributes, PKCS11_CKA_TOKEN)) { + EMSG("Persistent object not yet supported, panic!"); + TEE_Panic(0); + } else { + rc = PKCS11_CKR_OK; + LIST_INSERT_HEAD(get_session_objects(session), obj, link); + } + + *out_handle = obj_handle; + + return PKCS11_CKR_OK; +err: + /* make sure that supplied "head" isn't freed */ + obj->attributes = NULL; + handle_put(&session->object_handle_db, obj_handle); + if (get_bool(head, PKCS11_CKA_TOKEN)) + cleanup_persistent_object(obj, session->token); + else + cleanup_volatile_obj_ref(obj); + + return rc; +} + +enum pkcs11_rc entry_create_object(struct pkcs11_client *client, + uint32_t ptypes, TEE_Param *params) +{ + const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_MEMREF_OUTPUT, + TEE_PARAM_TYPE_NONE); + enum pkcs11_rc rc = PKCS11_CKR_OK; + TEE_Param *ctrl = params; + TEE_Param *out = params + 2; + struct serialargs ctrlargs = { }; + struct pkcs11_session *session = NULL; + struct obj_attrs *head = NULL; + struct pkcs11_object_head *template = NULL; + uint32_t session_handle = 0; + size_t template_size = 0; + uint32_t obj_handle = 0; + + /* + * Collect the arguments of the request + */ + + if (!client || ptypes != exp_pt || + out->memref.size != sizeof(obj_handle)) + return PKCS11_CKR_ARGUMENTS_BAD; + + serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); + + rc = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t)); + if (rc) + return rc; + + rc = serialargs_alloc_get_attributes(&ctrlargs, &template); + if (rc) + return rc; + + if (serialargs_remaining_bytes(&ctrlargs)) { + rc = PKCS11_CKR_ARGUMENTS_BAD; + goto out; + } + + session = pkcs11_handle2session(session_handle, client); + if (!session) { + rc = PKCS11_CKR_SESSION_HANDLE_INVALID; + goto out; + } + + template_size = sizeof(*template) + template->attrs_size; + + /* + * Prepare a clean initial state for the requested object attributes. + * Free temporary template once done. + */ + rc = create_attributes_from_template(&head, template, template_size, + NULL, PKCS11_FUNCTION_IMPORT, + PKCS11_PROCESSING_IMPORT); + TEE_Free(template); + template = NULL; + if (rc) + goto out; + + /* + * Check target object attributes match target processing + * Check target object attributes match token state + */ + rc = check_created_attrs_against_processing(PKCS11_PROCESSING_IMPORT, + head); + if (rc) + goto out; + + rc = check_created_attrs_against_token(session, head); + if (rc) + goto out; + + /* + * At this stage the object is almost created: all its attributes are + * referenced in @head, including the key value and are assumed + * reliable. Now need to register it and get a handle for it. + */ + rc = create_object(session, head, &obj_handle); + if (rc) + goto out; + + /* + * Now obj_handle (through the related struct pkcs11_object + * instance) owns the serialised buffer that holds the object + * attributes. We clear reference in head to NULL as the serializer + * object is now referred from obj_handle. This allows smooth pass + * through free at function exit. + */ + head = NULL; + + TEE_MemMove(out->memref.buffer, &obj_handle, sizeof(obj_handle)); + out->memref.size = sizeof(obj_handle); + + DMSG("PKCS11 session %"PRIu32": import object %#"PRIx32, + session->handle, obj_handle); + +out: + TEE_Free(template); + TEE_Free(head); + + return rc; +} + +enum pkcs11_rc entry_destroy_object(struct pkcs11_client *client, + uint32_t ptypes, TEE_Param *params) +{ + const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE); + enum pkcs11_rc rc = PKCS11_CKR_OK; + TEE_Param *ctrl = params; + struct serialargs ctrlargs = { }; + uint32_t object_handle = 0; + struct pkcs11_session *session = NULL; + struct pkcs11_object *object = NULL; + uint32_t session_handle = 0; + + if (!client || ptypes != exp_pt) + return PKCS11_CKR_ARGUMENTS_BAD; + + serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); + + rc = serialargs_get_u32(&ctrlargs, &session_handle); + if (rc) + return rc; + + rc = serialargs_get_u32(&ctrlargs, &object_handle); + if (rc) + return rc; + + if (serialargs_remaining_bytes(&ctrlargs)) + return PKCS11_CKR_ARGUMENTS_BAD; + + session = pkcs11_handle2session(session_handle, client); + if (!session) + return PKCS11_CKR_SESSION_HANDLE_INVALID; + + object = pkcs11_handle2object(object_handle, session); + if (!object) + return PKCS11_CKR_OBJECT_HANDLE_INVALID; + + destroy_object(session, object, false); + + DMSG("PKCS11 session %"PRIu32": destroy object %#"PRIx32, + session->handle, object_handle); + + return rc; +} diff --git a/ta/pkcs11/src/object.h b/ta/pkcs11/src/object.h new file mode 100644 index 00000000..91559f06 --- /dev/null +++ b/ta/pkcs11/src/object.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2017-2020, Linaro Limited + */ + +#ifndef PKCS11_TA_OBJECT_H +#define PKCS11_TA_OBJECT_H + +#include <pkcs11_ta.h> +#include <sys/queue.h> +#include <tee_internal_api.h> + +struct obj_attrs; +struct pkcs11_client; +struct pkcs11_session; + +/* + * link: objects are referenced in a double-linked list + * attributes: pointer to the serialized object attributes + * key_handle: GPD TEE object handle if used in an operation + * key_type: GPD TEE key type (shortcut used for processing) + * uuid: object UUID in the persistent database if a persistent object, or NULL + * attribs_hdl: GPD TEE attributes handles if persistent object + */ +struct pkcs11_object { + LIST_ENTRY(pkcs11_object) link; + struct obj_attrs *attributes; + TEE_ObjectHandle key_handle; + uint32_t key_type; + TEE_UUID *uuid; + TEE_ObjectHandle attribs_hdl; +}; + +LIST_HEAD(object_list, pkcs11_object); + +struct pkcs11_object *pkcs11_handle2object(uint32_t client_handle, + struct pkcs11_session *session); + +uint32_t pkcs11_object2handle(struct pkcs11_object *obj, + struct pkcs11_session *session); + +struct pkcs11_object *create_token_object(struct obj_attrs *head, + TEE_UUID *uuid); + +enum pkcs11_rc create_object(void *session, struct obj_attrs *attributes, + uint32_t *handle); + +void destroy_object(struct pkcs11_session *session, + struct pkcs11_object *object, bool session_object_only); + +/* + * Entry function called from the PKCS11 command parser + */ +enum pkcs11_rc entry_create_object(struct pkcs11_client *client, + uint32_t ptypes, TEE_Param *params); + +enum pkcs11_rc entry_destroy_object(struct pkcs11_client *client, + uint32_t ptypes, TEE_Param *params); +#endif /*PKCS11_TA_OBJECT_H*/ diff --git a/ta/pkcs11/src/pkcs11_token.c b/ta/pkcs11/src/pkcs11_token.c index ea5e3048..39d81a0b 100644 --- a/ta/pkcs11/src/pkcs11_token.c +++ b/ta/pkcs11/src/pkcs11_token.c @@ -584,6 +584,9 @@ enum pkcs11_rc entry_ck_open_session(struct pkcs11_client *client, session->token = token; session->client = client; + LIST_INIT(&session->object_list); + handle_db_init(&session->object_handle_db); + set_session_state(client, session, readonly); TAILQ_INSERT_HEAD(&client->session_list, session, link); @@ -602,8 +605,14 @@ enum pkcs11_rc entry_ck_open_session(struct pkcs11_client *client, static void close_ck_session(struct pkcs11_session *session) { + /* No need to put object handles, the whole database is destroyed */ + while (!LIST_EMPTY(&session->object_list)) + destroy_object(session, + LIST_FIRST(&session->object_list), true); + TAILQ_REMOVE(&session->client->session_list, session, link); handle_put(&session->client->session_handle_db, session->handle); + handle_db_destroy(&session->object_handle_db); session->token->session_count--; if (pkcs11_session_is_read_write(session)) diff --git a/ta/pkcs11/src/pkcs11_token.h b/ta/pkcs11/src/pkcs11_token.h index 6797df58..84a15dbd 100644 --- a/ta/pkcs11/src/pkcs11_token.h +++ b/ta/pkcs11/src/pkcs11_token.h @@ -11,6 +11,8 @@ #include <utee_defines.h> #include "handle.h" +#include "object.h" +#include "pkcs11_attributes.h" /* Hard coded description */ #define PKCS11_SLOT_DESCRIPTION "OP-TEE PKCS11 TA" @@ -73,12 +75,14 @@ struct token_persistent_main { * @state - Pkcs11 login is public, user, SO or custom * @session_count - Counter for opened Pkcs11 sessions * @rw_session_count - Count for opened Pkcs11 read/write sessions + * @object_list - List of the object owned by the token * @db_main - Volatile copy of the persistent main database */ struct ck_token { enum pkcs11_token_state state; uint32_t session_count; uint32_t rw_session_count; + struct object_list object_list; /* Copy in RAM of the persistent database */ struct token_persistent_main *db_main; }; @@ -90,6 +94,8 @@ struct ck_token { * @client - Client the session belongs to * @token - Token this session belongs to * @handle - Identifier of the session published to the client + * @object_list - Entry of the session objects list + * @object_handle_db - Database for object handles published by the session * @state - R/W SO, R/W user, RO user, R/W public, RO public. */ struct pkcs11_session { @@ -97,6 +103,8 @@ struct pkcs11_session { struct pkcs11_client *client; struct ck_token *token; uint32_t handle; + struct object_list object_list; + struct handle_db object_handle_db; enum pkcs11_session_state state; }; @@ -157,6 +165,12 @@ static inline bool pkcs11_session_is_so(struct pkcs11_session *session) } static inline +struct object_list *pkcs11_get_session_objects(struct pkcs11_session *session) +{ + return &session->object_list; +} + +static inline struct ck_token *pkcs11_session2token(struct pkcs11_session *session) { return session->token; diff --git a/ta/pkcs11/src/sub.mk b/ta/pkcs11/src/sub.mk index 7681c5d6..c2d618a6 100644 --- a/ta/pkcs11/src/sub.mk +++ b/ta/pkcs11/src/sub.mk @@ -1,6 +1,7 @@ srcs-y += attributes.c srcs-y += entry.c srcs-y += handle.c +srcs-y += object.c srcs-y += persistent_token.c srcs-y += pkcs11_attributes.c srcs-y += pkcs11_helpers.c |