diff --git a/ta/pkcs11/src/attributes.c b/ta/pkcs11/src/attributes.c index 9968985386a..ce357260ef1 100644 --- a/ta/pkcs11/src/attributes.c +++ b/ta/pkcs11/src/attributes.c @@ -381,6 +381,22 @@ enum pkcs11_rc get_attribute(struct obj_attrs *head, uint32_t attribute, return PKCS11_CKR_OK; } +enum pkcs11_rc set_attribute(struct obj_attrs **head, uint32_t attribute, + void *data, size_t size) +{ + enum pkcs11_rc rc = PKCS11_CKR_OK; + + rc = remove_attribute_check(head, attribute, 1); + if (rc != PKCS11_CKR_OK && rc != PKCS11_RV_NOT_FOUND) + return rc; + + rc = add_attribute(head, attribute, data, size); + if (rc) + return rc; + + return PKCS11_CKR_OK; +} + bool get_bool(struct obj_attrs *head, uint32_t attribute) { enum pkcs11_rc rc = PKCS11_CKR_OK; diff --git a/ta/pkcs11/src/attributes.h b/ta/pkcs11/src/attributes.h index 8894559b9d1..f19c550e6ef 100644 --- a/ta/pkcs11/src/attributes.h +++ b/ta/pkcs11/src/attributes.h @@ -196,6 +196,20 @@ enum pkcs11_rc get_attribute_ptr(struct obj_attrs *head, uint32_t attribute, enum pkcs11_rc get_attribute(struct obj_attrs *head, uint32_t attribute, void *attr, uint32_t *attr_size); +/* + * set_attribute() - Set serialized attributes. + * + * @head: *@head points to serialized attributes, + * can be reallocated as attributes are added + * @attribute: Attribute ID to set + * @data: Opaque data of attribute + * @size: Size of data + * + * Return PKCS11_CKR_OK on success or a PKCS11 return code. + */ +enum pkcs11_rc set_attribute(struct obj_attrs **head, uint32_t attribute, + void *data, size_t size); + /* * get_u32_attribute() - Copy out the 32-bit attribute value of a given ID * @head: Pointer to serialized attributes diff --git a/ta/pkcs11/src/entry.c b/ta/pkcs11/src/entry.c index 47d71e9f147..78a9817750d 100644 --- a/ta/pkcs11/src/entry.c +++ b/ta/pkcs11/src/entry.c @@ -307,6 +307,9 @@ TEE_Result TA_InvokeCommandEntryPoint(void *tee_session, uint32_t cmd, case PKCS11_CMD_GET_ATTRIBUTE_VALUE: rc = entry_get_attribute_value(client, ptypes, params); break; + case PKCS11_CMD_SET_ATTRIBUTE_VALUE: + rc = entry_set_attribute_value(client, ptypes, params); + break; case PKCS11_CMD_GET_OBJECT_SIZE: rc = entry_get_object_size(client, ptypes, params); break; diff --git a/ta/pkcs11/src/object.c b/ta/pkcs11/src/object.c index 4fd5a398b36..2e31caf0de2 100644 --- a/ta/pkcs11/src/object.c +++ b/ta/pkcs11/src/object.c @@ -948,6 +948,134 @@ uint32_t entry_get_attribute_value(struct pkcs11_client *client, return rc; } +uint32_t entry_set_attribute_value(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); + TEE_Param *ctrl = params; + enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR; + struct serialargs ctrlargs = { }; + struct pkcs11_session *session = NULL; + struct pkcs11_object_head *template = NULL; + struct pkcs11_object *obj = NULL; + uint32_t object_handle = 0; + char *cur = NULL; + size_t len = 0; + char *end = NULL; + bool modifiable = 0; + + if (!client || ptypes != exp_pt) + return PKCS11_CKR_ARGUMENTS_BAD; + + serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); + + rc = serialargs_get_session_from_handle(&ctrlargs, client, &session); + if (rc) + return rc; + + rc = serialargs_get(&ctrlargs, &object_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; + } + + obj = pkcs11_handle2object(object_handle, session); + if (!obj) { + rc = PKCS11_CKR_OBJECT_HANDLE_INVALID; + goto out; + } + + /* + * 1. Modifications to object with secret details from public session + * is denied. On failure returns PKCS11_CKR_OBJECT_HANDLE_INVALID + * (to hide presence of object) + * + * 2. If object is not modifiable then access is denied. On failure + * returns CKR_ACTION_PROHIBITED + * + * 3. Perform rule check for common variables to verify if value can be + * changed. On failure returns CKR_TEMPLATE_INCONSISTENT. + * + * 4. Depending on object type additional mechanisms consistency checks + * need to be performed. On failure returns + * CKR_TEMPLATE_INCONSISTENT. + */ + + /* 1. Verify that proper session is used for accessing the object */ + rc = check_access_attrs_against_token(session, obj->attributes); + if (rc) { + rc = PKCS11_CKR_OBJECT_HANDLE_INVALID; + goto out; + } + + /* 2. Verify that object can be modified. */ + modifiable = object_is_modifiable(obj->attributes); + if (!modifiable) { + rc = PKCS11_CKR_ACTION_PROHIBITED; + goto out; + } + + /* 3. iterate over attributes and check if we can set their values */ + cur = (char *)template + sizeof(struct pkcs11_object_head); + end = cur + template->attrs_size; + + for (; cur < end; cur += len) { + struct pkcs11_attribute_head *cli_ref = + (struct pkcs11_attribute_head *)cur; + + len = sizeof(*cli_ref) + cli_ref->size; + + if (!attribute_is_settable(cli_ref, obj)) { + rc = PKCS11_CKR_TEMPLATE_INCONSISTENT; + goto out; + } + } + + /* 4. TODO: mechanism consistency checks */ + + /* Everything is OK perform set operations */ + + /* iterate over attributes and set their values */ + cur = (char *)template + sizeof(struct pkcs11_object_head); + end = cur + template->attrs_size; + + for (; cur < end; cur += len) { + struct pkcs11_attribute_head *cli_ref = + (struct pkcs11_attribute_head *)cur; + + len = sizeof(*cli_ref) + cli_ref->size; + + /* + * We assume that if size is 0, pValue was NULL, so we return + * the size of the required buffer for it (3., 4.) + */ + rc = set_attribute(&obj->attributes, cli_ref->id, + cli_ref->size ? cli_ref->data : NULL, + cli_ref->size); + if (rc) + goto out; + } + + DMSG("PKCS11 session %"PRIu32": set attributes %#"PRIx32, + session->handle, object_handle); + +out: + TEE_Free(template); + template = NULL; + + return rc; +} + uint32_t entry_get_object_size(struct pkcs11_client *client, uint32_t ptypes, TEE_Param *params) { diff --git a/ta/pkcs11/src/object.h b/ta/pkcs11/src/object.h index 97d86b6a468..332930387d2 100644 --- a/ta/pkcs11/src/object.h +++ b/ta/pkcs11/src/object.h @@ -69,6 +69,9 @@ enum pkcs11_rc entry_find_objects_final(struct pkcs11_client *client, enum pkcs11_rc entry_get_attribute_value(struct pkcs11_client *client, uint32_t ptypes, TEE_Param *params); +enum pkcs11_rc entry_set_attribute_value(struct pkcs11_client *client, + uint32_t ptypes, TEE_Param *params); + enum pkcs11_rc entry_get_object_size(struct pkcs11_client *client, uint32_t ptypes, TEE_Param *params); diff --git a/ta/pkcs11/src/pkcs11_attributes.c b/ta/pkcs11/src/pkcs11_attributes.c index d02bf1aac64..949f2a442bf 100644 --- a/ta/pkcs11/src/pkcs11_attributes.c +++ b/ta/pkcs11/src/pkcs11_attributes.c @@ -1445,6 +1445,11 @@ bool object_is_private(struct obj_attrs *head) return false; } +bool object_is_modifiable(struct obj_attrs *head) +{ + return get_bool(head, PKCS11_CKA_MODIFIABLE); +} + /* * Add a CKA ID attribute to an object or paired object if missing. * If 2 objects are provided and at least 1 does not have a CKA_ID, @@ -1541,3 +1546,34 @@ bool attribute_is_exportable(struct pkcs11_attribute_head *req_attr, return true; } + +bool attribute_is_settable(struct pkcs11_attribute_head *req_attr, + struct pkcs11_object *obj) +{ + uint8_t boolval = 0; + uint32_t boolsize = 0; + enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR; + + switch (req_attr->id) { + case PKCS11_CKA_SENSITIVE: + /* Only allow change from CK_FALSE -> CK_TRUE */ + boolsize = sizeof(boolval); + rc = get_attribute(obj->attributes, PKCS11_CKA_SENSITIVE, + &boolval, &boolsize); + if (rc || boolval == PKCS11_TRUE) + return false; + break; + + case PKCS11_CKA_EXTRACTABLE: + /* Only allow change from CK_TRUE -> CK_FALSE */ + boolsize = sizeof(boolval); + rc = get_attribute(obj->attributes, PKCS11_CKA_EXTRACTABLE, + &boolval, &boolsize); + if (rc || boolval == PKCS11_FALSE) + return false; + break; + default: + break; + } + return true; +} diff --git a/ta/pkcs11/src/pkcs11_attributes.h b/ta/pkcs11/src/pkcs11_attributes.h index da838a0f227..a1f8f6defeb 100644 --- a/ta/pkcs11/src/pkcs11_attributes.h +++ b/ta/pkcs11/src/pkcs11_attributes.h @@ -166,9 +166,14 @@ check_mechanism_against_processing(struct pkcs11_session *session, bool object_is_private(struct obj_attrs *head); +bool object_is_modifiable(struct obj_attrs *head); + bool attribute_is_exportable(struct pkcs11_attribute_head *req_attr, struct pkcs11_object *obj); +bool attribute_is_settable(struct pkcs11_attribute_head *req_attr, + struct pkcs11_object *obj); + enum pkcs11_rc add_missing_attribute_id(struct obj_attrs **attrs1, struct obj_attrs **attrs2);