xref: /optee_os/ta/pkcs11/src/object.c (revision 402d884a797bb8a6ebf3d865fb6124b24ac24be3)
1b56b3d07SJens Wiklander // SPDX-License-Identifier: BSD-2-Clause
2b56b3d07SJens Wiklander /*
3b56b3d07SJens Wiklander  * Copyright (c) 2017-2020, Linaro Limited
4b56b3d07SJens Wiklander  */
5b56b3d07SJens Wiklander 
6b56b3d07SJens Wiklander #include <assert.h>
7b56b3d07SJens Wiklander #include <inttypes.h>
8b56b3d07SJens Wiklander #include <string_ext.h>
9b56b3d07SJens Wiklander #include <tee_internal_api.h>
10b56b3d07SJens Wiklander #include <tee_internal_api_extensions.h>
11b56b3d07SJens Wiklander 
12b56b3d07SJens Wiklander #include "attributes.h"
13b56b3d07SJens Wiklander #include "handle.h"
14b56b3d07SJens Wiklander #include "object.h"
15b56b3d07SJens Wiklander #include "pkcs11_attributes.h"
16b56b3d07SJens Wiklander #include "pkcs11_helpers.h"
17b56b3d07SJens Wiklander #include "pkcs11_token.h"
18b56b3d07SJens Wiklander #include "sanitize_object.h"
19b56b3d07SJens Wiklander #include "serializer.h"
20b56b3d07SJens Wiklander 
21b56b3d07SJens Wiklander struct pkcs11_object *pkcs11_handle2object(uint32_t handle,
22b56b3d07SJens Wiklander 					   struct pkcs11_session *session)
23b56b3d07SJens Wiklander {
24b56b3d07SJens Wiklander 	return handle_lookup(&session->object_handle_db, handle);
25b56b3d07SJens Wiklander }
26b56b3d07SJens Wiklander 
27b56b3d07SJens Wiklander uint32_t pkcs11_object2handle(struct pkcs11_object *obj,
28b56b3d07SJens Wiklander 			      struct pkcs11_session *session)
29b56b3d07SJens Wiklander {
30b56b3d07SJens Wiklander 	return handle_lookup_handle(&session->object_handle_db, obj);
31b56b3d07SJens Wiklander }
32b56b3d07SJens Wiklander 
33b56b3d07SJens Wiklander /* Currently handle pkcs11 sessions and tokens */
34b56b3d07SJens Wiklander 
35b56b3d07SJens Wiklander static struct object_list *get_session_objects(void *session)
36b56b3d07SJens Wiklander {
37b56b3d07SJens Wiklander 	/* Currently supporting only pkcs11 session */
38b56b3d07SJens Wiklander 	struct pkcs11_session *ck_session = session;
39b56b3d07SJens Wiklander 
40b56b3d07SJens Wiklander 	return pkcs11_get_session_objects(ck_session);
41b56b3d07SJens Wiklander }
42b56b3d07SJens Wiklander 
43334316feSJens Wiklander static struct ck_token *get_session_token(void *session)
44334316feSJens Wiklander {
45334316feSJens Wiklander 	struct pkcs11_session *ck_session = session;
46334316feSJens Wiklander 
47334316feSJens Wiklander 	return pkcs11_session2token(ck_session);
48334316feSJens Wiklander }
49334316feSJens Wiklander 
50b56b3d07SJens Wiklander /* Release resources of a non-persistent object */
51b56b3d07SJens Wiklander static void cleanup_volatile_obj_ref(struct pkcs11_object *obj)
52b56b3d07SJens Wiklander {
53b56b3d07SJens Wiklander 	if (!obj)
54b56b3d07SJens Wiklander 		return;
55b56b3d07SJens Wiklander 
56b56b3d07SJens Wiklander 	if (obj->key_handle != TEE_HANDLE_NULL)
57b56b3d07SJens Wiklander 		TEE_FreeTransientObject(obj->key_handle);
58b56b3d07SJens Wiklander 
59b56b3d07SJens Wiklander 	if (obj->attribs_hdl != TEE_HANDLE_NULL)
60b56b3d07SJens Wiklander 		TEE_CloseObject(obj->attribs_hdl);
61b56b3d07SJens Wiklander 
62b56b3d07SJens Wiklander 	TEE_Free(obj->attributes);
63b56b3d07SJens Wiklander 	TEE_Free(obj->uuid);
64b56b3d07SJens Wiklander 	TEE_Free(obj);
65b56b3d07SJens Wiklander }
66b56b3d07SJens Wiklander 
67b56b3d07SJens Wiklander /* Release resources of a persistent object including volatile resources */
687f12c782SRobin van der Gracht void cleanup_persistent_object(struct pkcs11_object *obj,
69334316feSJens Wiklander 			       struct ck_token *token)
70b56b3d07SJens Wiklander {
71334316feSJens Wiklander 	TEE_Result res = TEE_SUCCESS;
72334316feSJens Wiklander 
73334316feSJens Wiklander 	if (!obj)
74334316feSJens Wiklander 		return;
75334316feSJens Wiklander 
76334316feSJens Wiklander 	/* Open handle with write properties to destroy the object */
77334316feSJens Wiklander 	if (obj->attribs_hdl != TEE_HANDLE_NULL)
78334316feSJens Wiklander 		TEE_CloseObject(obj->attribs_hdl);
79334316feSJens Wiklander 
80334316feSJens Wiklander 	res = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE,
81334316feSJens Wiklander 				       obj->uuid, sizeof(TEE_UUID),
82334316feSJens Wiklander 				       TEE_DATA_FLAG_ACCESS_WRITE_META,
83334316feSJens Wiklander 				       &obj->attribs_hdl);
84334316feSJens Wiklander 	if (!res)
85334316feSJens Wiklander 		TEE_CloseAndDeletePersistentObject1(obj->attribs_hdl);
86334316feSJens Wiklander 
87334316feSJens Wiklander 	obj->attribs_hdl = TEE_HANDLE_NULL;
88334316feSJens Wiklander 	destroy_object_uuid(token, obj);
89334316feSJens Wiklander 
90334316feSJens Wiklander 	LIST_REMOVE(obj, link);
91334316feSJens Wiklander 
92334316feSJens Wiklander 	cleanup_volatile_obj_ref(obj);
93b56b3d07SJens Wiklander }
94b56b3d07SJens Wiklander 
95b56b3d07SJens Wiklander /*
96b56b3d07SJens Wiklander  * destroy_object - destroy an PKCS11 TA object
97b56b3d07SJens Wiklander  *
98b56b3d07SJens Wiklander  * @session - session requesting object destruction
99b56b3d07SJens Wiklander  * @obj - reference to the PKCS11 TA object
100b56b3d07SJens Wiklander  * @session_only - true if only session object shall be destroyed
101b56b3d07SJens Wiklander  */
102b56b3d07SJens Wiklander void destroy_object(struct pkcs11_session *session, struct pkcs11_object *obj,
103b56b3d07SJens Wiklander 		    bool session_only)
104b56b3d07SJens Wiklander {
105b56b3d07SJens Wiklander #ifdef DEBUG
106b56b3d07SJens Wiklander 	trace_attributes("[destroy]", obj->attributes);
107b56b3d07SJens Wiklander 	if (obj->uuid)
108b56b3d07SJens Wiklander 		MSG_RAW("[destroy] obj uuid %pUl", (void *)obj->uuid);
109b56b3d07SJens Wiklander #endif
110b56b3d07SJens Wiklander 
111b56b3d07SJens Wiklander 	/*
112b56b3d07SJens Wiklander 	 * Remove from session list only if it was published.
113b56b3d07SJens Wiklander 	 *
114b56b3d07SJens Wiklander 	 * This depends on obj->link.le_prev always pointing on the
115b56b3d07SJens Wiklander 	 * link.le_next element in the previous object in the list even if
116b56b3d07SJens Wiklander 	 * there's only a single object in the list. In the first object in
117b56b3d07SJens Wiklander 	 * the list obj->link.le_prev instead points to lh_first in the
118b56b3d07SJens Wiklander 	 * list head. If list implementation is changed we need to revisit
119b56b3d07SJens Wiklander 	 * this.
120b56b3d07SJens Wiklander 	 */
121b56b3d07SJens Wiklander 	if (obj->link.le_next || obj->link.le_prev)
122b56b3d07SJens Wiklander 		LIST_REMOVE(obj, link);
123b56b3d07SJens Wiklander 
124b56b3d07SJens Wiklander 	if (session_only) {
125b56b3d07SJens Wiklander 		/* Destroy object due to session closure */
126b56b3d07SJens Wiklander 		handle_put(&session->object_handle_db,
127b56b3d07SJens Wiklander 			   pkcs11_object2handle(obj, session));
128b56b3d07SJens Wiklander 		cleanup_volatile_obj_ref(obj);
129b56b3d07SJens Wiklander 
130b56b3d07SJens Wiklander 		return;
131b56b3d07SJens Wiklander 	}
132b56b3d07SJens Wiklander 
133b56b3d07SJens Wiklander 	/* Destroy target object (persistent or not) */
134b56b3d07SJens Wiklander 	if (get_bool(obj->attributes, PKCS11_CKA_TOKEN)) {
135334316feSJens Wiklander 		assert(obj->uuid);
136334316feSJens Wiklander 		/* Try twice otherwise panic! */
137334316feSJens Wiklander 		if (unregister_persistent_object(session->token, obj->uuid) &&
138334316feSJens Wiklander 		    unregister_persistent_object(session->token, obj->uuid))
139b56b3d07SJens Wiklander 			TEE_Panic(0);
140334316feSJens Wiklander 
141334316feSJens Wiklander 		handle_put(&session->object_handle_db,
142334316feSJens Wiklander 			   pkcs11_object2handle(obj, session));
143334316feSJens Wiklander 		cleanup_persistent_object(obj, session->token);
144b56b3d07SJens Wiklander 	} else {
145b56b3d07SJens Wiklander 		handle_put(&session->object_handle_db,
146b56b3d07SJens Wiklander 			   pkcs11_object2handle(obj, session));
147b56b3d07SJens Wiklander 		cleanup_volatile_obj_ref(obj);
148b56b3d07SJens Wiklander 	}
149b56b3d07SJens Wiklander }
150b56b3d07SJens Wiklander 
151b56b3d07SJens Wiklander static struct pkcs11_object *create_obj_instance(struct obj_attrs *head)
152b56b3d07SJens Wiklander {
153b56b3d07SJens Wiklander 	struct pkcs11_object *obj = NULL;
154b56b3d07SJens Wiklander 
155b56b3d07SJens Wiklander 	obj = TEE_Malloc(sizeof(struct pkcs11_object), TEE_MALLOC_FILL_ZERO);
156b56b3d07SJens Wiklander 	if (!obj)
157b56b3d07SJens Wiklander 		return NULL;
158b56b3d07SJens Wiklander 
159b56b3d07SJens Wiklander 	obj->key_handle = TEE_HANDLE_NULL;
160b56b3d07SJens Wiklander 	obj->attribs_hdl = TEE_HANDLE_NULL;
161b56b3d07SJens Wiklander 	obj->attributes = head;
162b56b3d07SJens Wiklander 
163b56b3d07SJens Wiklander 	return obj;
164b56b3d07SJens Wiklander }
165b56b3d07SJens Wiklander 
166334316feSJens Wiklander struct pkcs11_object *create_token_object(struct obj_attrs *head,
167334316feSJens Wiklander 					  TEE_UUID *uuid)
168334316feSJens Wiklander {
169334316feSJens Wiklander 	struct pkcs11_object *obj = create_obj_instance(head);
170334316feSJens Wiklander 
171334316feSJens Wiklander 	if (obj)
172334316feSJens Wiklander 		obj->uuid = uuid;
173334316feSJens Wiklander 
174334316feSJens Wiklander 	return obj;
175334316feSJens Wiklander }
176334316feSJens Wiklander 
177b56b3d07SJens Wiklander /*
178b56b3d07SJens Wiklander  * create_object - create an PKCS11 TA object from its attributes and value
179b56b3d07SJens Wiklander  *
180b56b3d07SJens Wiklander  * @sess - session requesting object creation
181b56b3d07SJens Wiklander  * @head - reference to serialized attributes
182b56b3d07SJens Wiklander  * @out_handle - generated handle for the created object
183b56b3d07SJens Wiklander  */
184b56b3d07SJens Wiklander enum pkcs11_rc create_object(void *sess, struct obj_attrs *head,
185b56b3d07SJens Wiklander 			     uint32_t *out_handle)
186b56b3d07SJens Wiklander {
187fde67b24SEtienne Carriere 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
188b56b3d07SJens Wiklander 	struct pkcs11_object *obj = NULL;
189b56b3d07SJens Wiklander 	struct pkcs11_session *session = (struct pkcs11_session *)sess;
190b56b3d07SJens Wiklander 	uint32_t obj_handle = 0;
191b56b3d07SJens Wiklander 
192b56b3d07SJens Wiklander #ifdef DEBUG
193b56b3d07SJens Wiklander 	trace_attributes("[create]", head);
194b56b3d07SJens Wiklander #endif
195b56b3d07SJens Wiklander 
196b56b3d07SJens Wiklander 	/*
197b56b3d07SJens Wiklander 	 * We do not check the key attributes. At this point, key attributes
198b56b3d07SJens Wiklander 	 * are expected consistent and reliable.
199b56b3d07SJens Wiklander 	 */
200b56b3d07SJens Wiklander 
201b56b3d07SJens Wiklander 	obj = create_obj_instance(head);
202b56b3d07SJens Wiklander 	if (!obj)
203b56b3d07SJens Wiklander 		return PKCS11_CKR_DEVICE_MEMORY;
204b56b3d07SJens Wiklander 
205b56b3d07SJens Wiklander 	/* Create a handle for the object in the session database */
206b56b3d07SJens Wiklander 	obj_handle = handle_get(&session->object_handle_db, obj);
207b56b3d07SJens Wiklander 	if (!obj_handle) {
208b56b3d07SJens Wiklander 		rc = PKCS11_CKR_DEVICE_MEMORY;
209b56b3d07SJens Wiklander 		goto err;
210b56b3d07SJens Wiklander 	}
211b56b3d07SJens Wiklander 
212b56b3d07SJens Wiklander 	if (get_bool(obj->attributes, PKCS11_CKA_TOKEN)) {
213334316feSJens Wiklander 		TEE_Result res = TEE_SUCCESS;
214334316feSJens Wiklander 
215334316feSJens Wiklander 		/*
216334316feSJens Wiklander 		 * Get an ID for the persistent object
217334316feSJens Wiklander 		 * Create the file
218334316feSJens Wiklander 		 * Register the object in the persistent database
219334316feSJens Wiklander 		 * (move the full sequence to persisent_db.c?)
220334316feSJens Wiklander 		 */
221334316feSJens Wiklander 		size_t size = sizeof(struct obj_attrs) +
222334316feSJens Wiklander 			      obj->attributes->attrs_size;
223334316feSJens Wiklander 		uint32_t tee_obj_flags = TEE_DATA_FLAG_ACCESS_READ |
224334316feSJens Wiklander 					 TEE_DATA_FLAG_ACCESS_WRITE |
225334316feSJens Wiklander 					 TEE_DATA_FLAG_ACCESS_WRITE_META;
226334316feSJens Wiklander 
227334316feSJens Wiklander 		rc = create_object_uuid(get_session_token(session), obj);
228334316feSJens Wiklander 		if (rc)
229334316feSJens Wiklander 			goto err;
230334316feSJens Wiklander 
231334316feSJens Wiklander 		res = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE,
232334316feSJens Wiklander 						 obj->uuid, sizeof(TEE_UUID),
233334316feSJens Wiklander 						 tee_obj_flags,
234334316feSJens Wiklander 						 TEE_HANDLE_NULL,
235334316feSJens Wiklander 						 obj->attributes, size,
236334316feSJens Wiklander 						 &obj->attribs_hdl);
237334316feSJens Wiklander 		if (res) {
238334316feSJens Wiklander 			rc = tee2pkcs_error(res);
239334316feSJens Wiklander 			goto err;
240334316feSJens Wiklander 		}
241334316feSJens Wiklander 
242334316feSJens Wiklander 		rc = register_persistent_object(get_session_token(session),
243334316feSJens Wiklander 						obj->uuid);
244334316feSJens Wiklander 		if (rc)
245334316feSJens Wiklander 			goto err;
246334316feSJens Wiklander 
2470fafe5c7SVesa Jääskeläinen 		TEE_CloseObject(obj->attribs_hdl);
2480fafe5c7SVesa Jääskeläinen 		obj->attribs_hdl = TEE_HANDLE_NULL;
2490fafe5c7SVesa Jääskeläinen 
250334316feSJens Wiklander 		LIST_INSERT_HEAD(&session->token->object_list, obj, link);
251b56b3d07SJens Wiklander 	} else {
252b56b3d07SJens Wiklander 		rc = PKCS11_CKR_OK;
253b56b3d07SJens Wiklander 		LIST_INSERT_HEAD(get_session_objects(session), obj, link);
254b56b3d07SJens Wiklander 	}
255b56b3d07SJens Wiklander 
256b56b3d07SJens Wiklander 	*out_handle = obj_handle;
257b56b3d07SJens Wiklander 
258b56b3d07SJens Wiklander 	return PKCS11_CKR_OK;
259b56b3d07SJens Wiklander err:
260b56b3d07SJens Wiklander 	/* make sure that supplied "head" isn't freed */
261b56b3d07SJens Wiklander 	obj->attributes = NULL;
262b56b3d07SJens Wiklander 	handle_put(&session->object_handle_db, obj_handle);
263b56b3d07SJens Wiklander 	if (get_bool(head, PKCS11_CKA_TOKEN))
264b56b3d07SJens Wiklander 		cleanup_persistent_object(obj, session->token);
265b56b3d07SJens Wiklander 	else
266b56b3d07SJens Wiklander 		cleanup_volatile_obj_ref(obj);
267b56b3d07SJens Wiklander 
268b56b3d07SJens Wiklander 	return rc;
269b56b3d07SJens Wiklander }
270b56b3d07SJens Wiklander 
271b56b3d07SJens Wiklander enum pkcs11_rc entry_create_object(struct pkcs11_client *client,
272b56b3d07SJens Wiklander 				   uint32_t ptypes, TEE_Param *params)
273b56b3d07SJens Wiklander {
274b56b3d07SJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
275b56b3d07SJens Wiklander 						TEE_PARAM_TYPE_NONE,
276b56b3d07SJens Wiklander 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
277b56b3d07SJens Wiklander 						TEE_PARAM_TYPE_NONE);
278b56b3d07SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
279b56b3d07SJens Wiklander 	TEE_Param *ctrl = params;
280b56b3d07SJens Wiklander 	TEE_Param *out = params + 2;
281b56b3d07SJens Wiklander 	struct serialargs ctrlargs = { };
282b56b3d07SJens Wiklander 	struct pkcs11_session *session = NULL;
283b56b3d07SJens Wiklander 	struct obj_attrs *head = NULL;
284b56b3d07SJens Wiklander 	struct pkcs11_object_head *template = NULL;
285b56b3d07SJens Wiklander 	size_t template_size = 0;
286b56b3d07SJens Wiklander 	uint32_t obj_handle = 0;
287b56b3d07SJens Wiklander 
288b56b3d07SJens Wiklander 	/*
289b56b3d07SJens Wiklander 	 * Collect the arguments of the request
290b56b3d07SJens Wiklander 	 */
291b56b3d07SJens Wiklander 
292b56b3d07SJens Wiklander 	if (!client || ptypes != exp_pt ||
293b56b3d07SJens Wiklander 	    out->memref.size != sizeof(obj_handle))
294b56b3d07SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
295b56b3d07SJens Wiklander 
296b56b3d07SJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
297b56b3d07SJens Wiklander 
29859a5257eSEtienne Carriere 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
299b56b3d07SJens Wiklander 	if (rc)
300b56b3d07SJens Wiklander 		return rc;
301b56b3d07SJens Wiklander 
302b56b3d07SJens Wiklander 	rc = serialargs_alloc_get_attributes(&ctrlargs, &template);
303b56b3d07SJens Wiklander 	if (rc)
304b56b3d07SJens Wiklander 		return rc;
305b56b3d07SJens Wiklander 
306b56b3d07SJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs)) {
307b56b3d07SJens Wiklander 		rc = PKCS11_CKR_ARGUMENTS_BAD;
308b56b3d07SJens Wiklander 		goto out;
309b56b3d07SJens Wiklander 	}
310b56b3d07SJens Wiklander 
311b56b3d07SJens Wiklander 	template_size = sizeof(*template) + template->attrs_size;
312b56b3d07SJens Wiklander 
313b56b3d07SJens Wiklander 	/*
314b56b3d07SJens Wiklander 	 * Prepare a clean initial state for the requested object attributes.
315b56b3d07SJens Wiklander 	 * Free temporary template once done.
316b56b3d07SJens Wiklander 	 */
317b56b3d07SJens Wiklander 	rc = create_attributes_from_template(&head, template, template_size,
318b56b3d07SJens Wiklander 					     NULL, PKCS11_FUNCTION_IMPORT,
3194cfce748SRuchika Gupta 					     PKCS11_PROCESSING_IMPORT,
3204cfce748SRuchika Gupta 					     PKCS11_CKO_UNDEFINED_ID);
321b56b3d07SJens Wiklander 	TEE_Free(template);
322b56b3d07SJens Wiklander 	template = NULL;
323b56b3d07SJens Wiklander 	if (rc)
324b56b3d07SJens Wiklander 		goto out;
325b56b3d07SJens Wiklander 
326b56b3d07SJens Wiklander 	/*
327b56b3d07SJens Wiklander 	 * Check target object attributes match target processing
328b56b3d07SJens Wiklander 	 * Check target object attributes match token state
329b56b3d07SJens Wiklander 	 */
330b56b3d07SJens Wiklander 	rc = check_created_attrs_against_processing(PKCS11_PROCESSING_IMPORT,
331b56b3d07SJens Wiklander 						    head);
332b56b3d07SJens Wiklander 	if (rc)
333b56b3d07SJens Wiklander 		goto out;
334b56b3d07SJens Wiklander 
335b56b3d07SJens Wiklander 	rc = check_created_attrs_against_token(session, head);
336b56b3d07SJens Wiklander 	if (rc)
337b56b3d07SJens Wiklander 		goto out;
338b56b3d07SJens Wiklander 
339b68aca61SRuchika Gupta 	rc = check_access_attrs_against_token(session, head);
340b68aca61SRuchika Gupta 	if (rc)
341b68aca61SRuchika Gupta 		goto out;
342b68aca61SRuchika Gupta 
343b56b3d07SJens Wiklander 	/*
344b56b3d07SJens Wiklander 	 * At this stage the object is almost created: all its attributes are
345b56b3d07SJens Wiklander 	 * referenced in @head, including the key value and are assumed
346b56b3d07SJens Wiklander 	 * reliable. Now need to register it and get a handle for it.
347b56b3d07SJens Wiklander 	 */
348b56b3d07SJens Wiklander 	rc = create_object(session, head, &obj_handle);
349b56b3d07SJens Wiklander 	if (rc)
350b56b3d07SJens Wiklander 		goto out;
351b56b3d07SJens Wiklander 
352b56b3d07SJens Wiklander 	/*
353b56b3d07SJens Wiklander 	 * Now obj_handle (through the related struct pkcs11_object
354e3737878SRuchika Gupta 	 * instance) owns the serialized buffer that holds the object
355b56b3d07SJens Wiklander 	 * attributes. We clear reference in head to NULL as the serializer
356b56b3d07SJens Wiklander 	 * object is now referred from obj_handle. This allows smooth pass
357b56b3d07SJens Wiklander 	 * through free at function exit.
358b56b3d07SJens Wiklander 	 */
359b56b3d07SJens Wiklander 	head = NULL;
360b56b3d07SJens Wiklander 
361b56b3d07SJens Wiklander 	TEE_MemMove(out->memref.buffer, &obj_handle, sizeof(obj_handle));
362b56b3d07SJens Wiklander 	out->memref.size = sizeof(obj_handle);
363b56b3d07SJens Wiklander 
364b56b3d07SJens Wiklander 	DMSG("PKCS11 session %"PRIu32": import object %#"PRIx32,
365b56b3d07SJens Wiklander 	     session->handle, obj_handle);
366b56b3d07SJens Wiklander 
367b56b3d07SJens Wiklander out:
368b56b3d07SJens Wiklander 	TEE_Free(template);
369b56b3d07SJens Wiklander 	TEE_Free(head);
370b56b3d07SJens Wiklander 
371b56b3d07SJens Wiklander 	return rc;
372b56b3d07SJens Wiklander }
373b56b3d07SJens Wiklander 
374b56b3d07SJens Wiklander enum pkcs11_rc entry_destroy_object(struct pkcs11_client *client,
375b56b3d07SJens Wiklander 				    uint32_t ptypes, TEE_Param *params)
376b56b3d07SJens Wiklander {
377b56b3d07SJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
378b56b3d07SJens Wiklander 						TEE_PARAM_TYPE_NONE,
379b56b3d07SJens Wiklander 						TEE_PARAM_TYPE_NONE,
380b56b3d07SJens Wiklander 						TEE_PARAM_TYPE_NONE);
381b56b3d07SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
382b56b3d07SJens Wiklander 	TEE_Param *ctrl = params;
383b56b3d07SJens Wiklander 	struct serialargs ctrlargs = { };
384b56b3d07SJens Wiklander 	uint32_t object_handle = 0;
385b56b3d07SJens Wiklander 	struct pkcs11_session *session = NULL;
386b56b3d07SJens Wiklander 	struct pkcs11_object *object = NULL;
387b56b3d07SJens Wiklander 
388b56b3d07SJens Wiklander 	if (!client || ptypes != exp_pt)
389b56b3d07SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
390b56b3d07SJens Wiklander 
391b56b3d07SJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
392b56b3d07SJens Wiklander 
39359a5257eSEtienne Carriere 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
394b56b3d07SJens Wiklander 	if (rc)
395b56b3d07SJens Wiklander 		return rc;
396b56b3d07SJens Wiklander 
397b56b3d07SJens Wiklander 	rc = serialargs_get_u32(&ctrlargs, &object_handle);
398b56b3d07SJens Wiklander 	if (rc)
399b56b3d07SJens Wiklander 		return rc;
400b56b3d07SJens Wiklander 
401b56b3d07SJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs))
402b56b3d07SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
403b56b3d07SJens Wiklander 
404b56b3d07SJens Wiklander 	object = pkcs11_handle2object(object_handle, session);
405b56b3d07SJens Wiklander 	if (!object)
406b56b3d07SJens Wiklander 		return PKCS11_CKR_OBJECT_HANDLE_INVALID;
407b56b3d07SJens Wiklander 
408fab91492SRuchika Gupta 	/* Only session objects can be destroyed during a read-only session */
409fab91492SRuchika Gupta 	if (get_bool(object->attributes, PKCS11_CKA_TOKEN) &&
410fab91492SRuchika Gupta 	    !pkcs11_session_is_read_write(session)) {
411fab91492SRuchika Gupta 		DMSG("Can't destroy persistent object");
412fab91492SRuchika Gupta 		return PKCS11_CKR_SESSION_READ_ONLY;
413fab91492SRuchika Gupta 	}
414fab91492SRuchika Gupta 
415fab91492SRuchika Gupta 	/*
416fab91492SRuchika Gupta 	 * Only public objects can be destroyed unless normal user is logged in
417fab91492SRuchika Gupta 	 */
418fab91492SRuchika Gupta 	rc = check_access_attrs_against_token(session, object->attributes);
419fab91492SRuchika Gupta 	if (rc)
420fab91492SRuchika Gupta 		return PKCS11_CKR_USER_NOT_LOGGED_IN;
421fab91492SRuchika Gupta 
422fab91492SRuchika Gupta 	/* Objects with PKCS11_CKA_DESTROYABLE as false aren't destroyable */
423fab91492SRuchika Gupta 	if (!get_bool(object->attributes, PKCS11_CKA_DESTROYABLE))
424fab91492SRuchika Gupta 		return PKCS11_CKR_ACTION_PROHIBITED;
425fab91492SRuchika Gupta 
426b56b3d07SJens Wiklander 	destroy_object(session, object, false);
427b56b3d07SJens Wiklander 
428b56b3d07SJens Wiklander 	DMSG("PKCS11 session %"PRIu32": destroy object %#"PRIx32,
429b56b3d07SJens Wiklander 	     session->handle, object_handle);
430b56b3d07SJens Wiklander 
431b56b3d07SJens Wiklander 	return rc;
432b56b3d07SJens Wiklander }
433dc99b202SRuchika Gupta 
434dc99b202SRuchika Gupta static void release_find_obj_context(struct pkcs11_find_objects *find_ctx)
435dc99b202SRuchika Gupta {
436dc99b202SRuchika Gupta 	if (!find_ctx)
437dc99b202SRuchika Gupta 		return;
438dc99b202SRuchika Gupta 
439dc99b202SRuchika Gupta 	TEE_Free(find_ctx->attributes);
440dc99b202SRuchika Gupta 	TEE_Free(find_ctx->handles);
441dc99b202SRuchika Gupta 	TEE_Free(find_ctx);
442dc99b202SRuchika Gupta }
443dc99b202SRuchika Gupta 
444dc99b202SRuchika Gupta static enum pkcs11_rc find_ctx_add(struct pkcs11_find_objects *find_ctx,
445dc99b202SRuchika Gupta 				   uint32_t handle)
446dc99b202SRuchika Gupta {
447dc99b202SRuchika Gupta 	uint32_t *hdls = TEE_Realloc(find_ctx->handles,
448dc99b202SRuchika Gupta 				     (find_ctx->count + 1) * sizeof(*hdls));
449dc99b202SRuchika Gupta 
450dc99b202SRuchika Gupta 	if (!hdls)
451dc99b202SRuchika Gupta 		return PKCS11_CKR_DEVICE_MEMORY;
452dc99b202SRuchika Gupta 
453dc99b202SRuchika Gupta 	find_ctx->handles = hdls;
454dc99b202SRuchika Gupta 
455dc99b202SRuchika Gupta 	*(find_ctx->handles + find_ctx->count) = handle;
456dc99b202SRuchika Gupta 	find_ctx->count++;
457dc99b202SRuchika Gupta 
458dc99b202SRuchika Gupta 	return PKCS11_CKR_OK;
459dc99b202SRuchika Gupta }
460dc99b202SRuchika Gupta 
461dc99b202SRuchika Gupta enum pkcs11_rc entry_find_objects_init(struct pkcs11_client *client,
462dc99b202SRuchika Gupta 				       uint32_t ptypes, TEE_Param *params)
463dc99b202SRuchika Gupta {
464dc99b202SRuchika Gupta 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
465dc99b202SRuchika Gupta 						TEE_PARAM_TYPE_NONE,
466dc99b202SRuchika Gupta 						TEE_PARAM_TYPE_NONE,
467dc99b202SRuchika Gupta 						TEE_PARAM_TYPE_NONE);
468dc99b202SRuchika Gupta 	TEE_Param *ctrl = params;
469dc99b202SRuchika Gupta 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
470dc99b202SRuchika Gupta 	struct serialargs ctrlargs = { };
471dc99b202SRuchika Gupta 	struct pkcs11_session *session = NULL;
472dc99b202SRuchika Gupta 	struct pkcs11_object_head *template = NULL;
473dc99b202SRuchika Gupta 	struct obj_attrs *req_attrs = NULL;
474dc99b202SRuchika Gupta 	struct pkcs11_object *obj = NULL;
475dc99b202SRuchika Gupta 	struct pkcs11_find_objects *find_ctx = NULL;
476dc99b202SRuchika Gupta 
477dc99b202SRuchika Gupta 	if (!client || ptypes != exp_pt)
478dc99b202SRuchika Gupta 		return PKCS11_CKR_ARGUMENTS_BAD;
479dc99b202SRuchika Gupta 
480dc99b202SRuchika Gupta 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
481dc99b202SRuchika Gupta 
482dc99b202SRuchika Gupta 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
483dc99b202SRuchika Gupta 	if (rc)
484dc99b202SRuchika Gupta 		return rc;
485dc99b202SRuchika Gupta 
486dc99b202SRuchika Gupta 	rc = serialargs_alloc_get_attributes(&ctrlargs, &template);
487dc99b202SRuchika Gupta 	if (rc)
488dc99b202SRuchika Gupta 		return rc;
489dc99b202SRuchika Gupta 
490dc99b202SRuchika Gupta 	if (serialargs_remaining_bytes(&ctrlargs)) {
491dc99b202SRuchika Gupta 		rc = PKCS11_CKR_ARGUMENTS_BAD;
492dc99b202SRuchika Gupta 		goto out;
493dc99b202SRuchika Gupta 	}
494dc99b202SRuchika Gupta 
495dc99b202SRuchika Gupta 	/* Search objects only if no operation is on-going */
496dc99b202SRuchika Gupta 	if (session_is_active(session)) {
497dc99b202SRuchika Gupta 		rc = PKCS11_CKR_OPERATION_ACTIVE;
498dc99b202SRuchika Gupta 		goto out;
499dc99b202SRuchika Gupta 	}
500dc99b202SRuchika Gupta 
501dc99b202SRuchika Gupta 	if (session->find_ctx) {
502dc99b202SRuchika Gupta 		EMSG("Active object search already in progress");
503dc99b202SRuchika Gupta 		rc = PKCS11_CKR_FUNCTION_FAILED;
504dc99b202SRuchika Gupta 		goto out;
505dc99b202SRuchika Gupta 	}
506dc99b202SRuchika Gupta 
507dc99b202SRuchika Gupta 	rc = sanitize_client_object(&req_attrs, template,
508dc99b202SRuchika Gupta 				    sizeof(*template) + template->attrs_size,
509dc99b202SRuchika Gupta 				    PKCS11_UNDEFINED_ID, PKCS11_UNDEFINED_ID);
510dc99b202SRuchika Gupta 	if (rc)
511dc99b202SRuchika Gupta 		goto out;
512dc99b202SRuchika Gupta 
513dc99b202SRuchika Gupta 	/* Must zero init the structure */
514dc99b202SRuchika Gupta 	find_ctx = TEE_Malloc(sizeof(*find_ctx), TEE_MALLOC_FILL_ZERO);
515dc99b202SRuchika Gupta 	if (!find_ctx) {
516dc99b202SRuchika Gupta 		rc = PKCS11_CKR_DEVICE_MEMORY;
517dc99b202SRuchika Gupta 		goto out;
518dc99b202SRuchika Gupta 	}
519dc99b202SRuchika Gupta 
520dc99b202SRuchika Gupta 	TEE_Free(template);
521dc99b202SRuchika Gupta 	template = NULL;
522dc99b202SRuchika Gupta 
523dc99b202SRuchika Gupta 	switch (get_class(req_attrs)) {
524dc99b202SRuchika Gupta 	case PKCS11_CKO_UNDEFINED_ID:
525dc99b202SRuchika Gupta 	/* Unspecified class searches among data objects */
526dc99b202SRuchika Gupta 	case PKCS11_CKO_SECRET_KEY:
527dc99b202SRuchika Gupta 	case PKCS11_CKO_PUBLIC_KEY:
528dc99b202SRuchika Gupta 	case PKCS11_CKO_PRIVATE_KEY:
529dc99b202SRuchika Gupta 	case PKCS11_CKO_DATA:
530dc99b202SRuchika Gupta 		break;
531dc99b202SRuchika Gupta 	default:
532dc99b202SRuchika Gupta 		EMSG("Find object of class %s (%"PRIu32") is not supported",
533dc99b202SRuchika Gupta 		     id2str_class(get_class(req_attrs)),
534dc99b202SRuchika Gupta 		     get_class(req_attrs));
535dc99b202SRuchika Gupta 		rc = PKCS11_CKR_ARGUMENTS_BAD;
536dc99b202SRuchika Gupta 		goto out;
537dc99b202SRuchika Gupta 	}
538dc99b202SRuchika Gupta 
539dc99b202SRuchika Gupta 	/*
540dc99b202SRuchika Gupta 	 * Scan all objects (sessions and persistent ones) and set a list of
541dc99b202SRuchika Gupta 	 * candidates that match caller attributes.
542dc99b202SRuchika Gupta 	 */
543dc99b202SRuchika Gupta 
544dc99b202SRuchika Gupta 	LIST_FOREACH(obj, &session->object_list, link) {
545dc99b202SRuchika Gupta 		if (check_access_attrs_against_token(session, obj->attributes))
546dc99b202SRuchika Gupta 			continue;
547dc99b202SRuchika Gupta 
548fa1ac767SRobin van der Gracht 		if (!attributes_match_reference(obj->attributes, req_attrs))
549dc99b202SRuchika Gupta 			continue;
550dc99b202SRuchika Gupta 
551dc99b202SRuchika Gupta 		rc = find_ctx_add(find_ctx, pkcs11_object2handle(obj, session));
552dc99b202SRuchika Gupta 		if (rc)
553dc99b202SRuchika Gupta 			goto out;
554dc99b202SRuchika Gupta 	}
555dc99b202SRuchika Gupta 
556dc99b202SRuchika Gupta 	LIST_FOREACH(obj, &session->token->object_list, link) {
557dc99b202SRuchika Gupta 		uint32_t handle = 0;
558fa1ac767SRobin van der Gracht 		bool new_load = false;
559dc99b202SRuchika Gupta 
560fa1ac767SRobin van der Gracht 		if (!obj->attributes) {
561fa1ac767SRobin van der Gracht 			rc = load_persistent_object_attributes(obj);
562fa1ac767SRobin van der Gracht 			if (rc)
563fa1ac767SRobin van der Gracht 				return PKCS11_CKR_GENERAL_ERROR;
564dc99b202SRuchika Gupta 
565fa1ac767SRobin van der Gracht 			new_load = true;
566fa1ac767SRobin van der Gracht 		}
567fa1ac767SRobin van der Gracht 
568fa1ac767SRobin van der Gracht 		if (!obj->attributes ||
569fa1ac767SRobin van der Gracht 		    check_access_attrs_against_token(session,
570fa1ac767SRobin van der Gracht 						     obj->attributes) ||
571fa1ac767SRobin van der Gracht 		    !attributes_match_reference(obj->attributes, req_attrs)) {
572fa1ac767SRobin van der Gracht 			if (new_load)
573fa1ac767SRobin van der Gracht 				release_persistent_object_attributes(obj);
574fa1ac767SRobin van der Gracht 
575dc99b202SRuchika Gupta 			continue;
576dc99b202SRuchika Gupta 		}
577dc99b202SRuchika Gupta 
578dc99b202SRuchika Gupta 		/* Object may not yet be published in the session */
579dc99b202SRuchika Gupta 		handle = pkcs11_object2handle(obj, session);
580dc99b202SRuchika Gupta 		if (!handle) {
581dc99b202SRuchika Gupta 			handle = handle_get(&session->object_handle_db, obj);
582dc99b202SRuchika Gupta 			if (!handle) {
583dc99b202SRuchika Gupta 				rc = PKCS11_CKR_DEVICE_MEMORY;
584dc99b202SRuchika Gupta 				goto out;
585dc99b202SRuchika Gupta 			}
586dc99b202SRuchika Gupta 		}
587dc99b202SRuchika Gupta 
588dc99b202SRuchika Gupta 		rc = find_ctx_add(find_ctx, handle);
589dc99b202SRuchika Gupta 		if (rc)
590dc99b202SRuchika Gupta 			goto out;
591dc99b202SRuchika Gupta 	}
592dc99b202SRuchika Gupta 
593dc99b202SRuchika Gupta 	find_ctx->attributes = req_attrs;
594dc99b202SRuchika Gupta 	req_attrs = NULL;
595dc99b202SRuchika Gupta 	session->find_ctx = find_ctx;
596dc99b202SRuchika Gupta 	find_ctx = NULL;
597dc99b202SRuchika Gupta 	rc = PKCS11_CKR_OK;
598dc99b202SRuchika Gupta 
599dc99b202SRuchika Gupta out:
600dc99b202SRuchika Gupta 	TEE_Free(req_attrs);
601dc99b202SRuchika Gupta 	TEE_Free(template);
602dc99b202SRuchika Gupta 	release_find_obj_context(find_ctx);
603dc99b202SRuchika Gupta 
604dc99b202SRuchika Gupta 	return rc;
605dc99b202SRuchika Gupta }
606dc99b202SRuchika Gupta 
607dc99b202SRuchika Gupta enum pkcs11_rc entry_find_objects(struct pkcs11_client *client,
608dc99b202SRuchika Gupta 				  uint32_t ptypes, TEE_Param *params)
609dc99b202SRuchika Gupta {
610dc99b202SRuchika Gupta 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
611dc99b202SRuchika Gupta 						TEE_PARAM_TYPE_NONE,
612dc99b202SRuchika Gupta 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
613dc99b202SRuchika Gupta 						TEE_PARAM_TYPE_NONE);
614dc99b202SRuchika Gupta 	TEE_Param *ctrl = params;
615dc99b202SRuchika Gupta 	TEE_Param *out = params + 2;
616dc99b202SRuchika Gupta 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
617dc99b202SRuchika Gupta 	struct serialargs ctrlargs = { };
618dc99b202SRuchika Gupta 	struct pkcs11_session *session = NULL;
619dc99b202SRuchika Gupta 	struct pkcs11_find_objects *ctx = NULL;
620dc99b202SRuchika Gupta 	uint8_t *out_handles = NULL;
621dc99b202SRuchika Gupta 	size_t out_count = 0;
622dc99b202SRuchika Gupta 	size_t count = 0;
623dc99b202SRuchika Gupta 
624dc99b202SRuchika Gupta 	if (!client || ptypes != exp_pt)
625dc99b202SRuchika Gupta 		return PKCS11_CKR_ARGUMENTS_BAD;
626dc99b202SRuchika Gupta 
627dc99b202SRuchika Gupta 	out_count = out->memref.size / sizeof(uint32_t);
628dc99b202SRuchika Gupta 	out_handles = out->memref.buffer;
629dc99b202SRuchika Gupta 
630dc99b202SRuchika Gupta 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
631dc99b202SRuchika Gupta 
632dc99b202SRuchika Gupta 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
633dc99b202SRuchika Gupta 	if (rc)
634dc99b202SRuchika Gupta 		return rc;
635dc99b202SRuchika Gupta 
636dc99b202SRuchika Gupta 	if (serialargs_remaining_bytes(&ctrlargs))
637dc99b202SRuchika Gupta 		return PKCS11_CKR_ARGUMENTS_BAD;
638dc99b202SRuchika Gupta 
639dc99b202SRuchika Gupta 	ctx = session->find_ctx;
640dc99b202SRuchika Gupta 
641dc99b202SRuchika Gupta 	if (!ctx)
642dc99b202SRuchika Gupta 		return PKCS11_CKR_OPERATION_NOT_INITIALIZED;
643dc99b202SRuchika Gupta 
644dc99b202SRuchika Gupta 	for (count = 0; ctx->next < ctx->count && count < out_count;
645dc99b202SRuchika Gupta 	     ctx->next++, count++)
646dc99b202SRuchika Gupta 		TEE_MemMove(out_handles + count * sizeof(uint32_t),
647dc99b202SRuchika Gupta 			    ctx->handles + ctx->next, sizeof(uint32_t));
648dc99b202SRuchika Gupta 
649dc99b202SRuchika Gupta 	/* Update output buffer according the number of handles provided */
650dc99b202SRuchika Gupta 	out->memref.size = count * sizeof(uint32_t);
651dc99b202SRuchika Gupta 
652dc99b202SRuchika Gupta 	DMSG("PKCS11 session %"PRIu32": finding objects", session->handle);
653dc99b202SRuchika Gupta 
654dc99b202SRuchika Gupta 	return PKCS11_CKR_OK;
655dc99b202SRuchika Gupta }
656dc99b202SRuchika Gupta 
657dc99b202SRuchika Gupta void release_session_find_obj_context(struct pkcs11_session *session)
658dc99b202SRuchika Gupta {
659dc99b202SRuchika Gupta 	release_find_obj_context(session->find_ctx);
660dc99b202SRuchika Gupta 	session->find_ctx = NULL;
661dc99b202SRuchika Gupta }
662dc99b202SRuchika Gupta 
663e3737878SRuchika Gupta enum pkcs11_rc entry_find_objects_final(struct pkcs11_client *client,
664dc99b202SRuchika Gupta 					uint32_t ptypes, TEE_Param *params)
665dc99b202SRuchika Gupta {
666dc99b202SRuchika Gupta 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
667dc99b202SRuchika Gupta 						TEE_PARAM_TYPE_NONE,
668dc99b202SRuchika Gupta 						TEE_PARAM_TYPE_NONE,
669dc99b202SRuchika Gupta 						TEE_PARAM_TYPE_NONE);
670dc99b202SRuchika Gupta 	TEE_Param *ctrl = params;
671dc99b202SRuchika Gupta 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
672dc99b202SRuchika Gupta 	struct serialargs ctrlargs = { };
673dc99b202SRuchika Gupta 	struct pkcs11_session *session = NULL;
674dc99b202SRuchika Gupta 
675dc99b202SRuchika Gupta 	if (!client || ptypes != exp_pt)
676dc99b202SRuchika Gupta 		return PKCS11_CKR_ARGUMENTS_BAD;
677dc99b202SRuchika Gupta 
678dc99b202SRuchika Gupta 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
679dc99b202SRuchika Gupta 
680dc99b202SRuchika Gupta 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
681dc99b202SRuchika Gupta 	if (rc)
682dc99b202SRuchika Gupta 		return rc;
683dc99b202SRuchika Gupta 
684dc99b202SRuchika Gupta 	if (serialargs_remaining_bytes(&ctrlargs))
685dc99b202SRuchika Gupta 		return PKCS11_CKR_ARGUMENTS_BAD;
686dc99b202SRuchika Gupta 
687dc99b202SRuchika Gupta 	if (!session->find_ctx)
688dc99b202SRuchika Gupta 		return PKCS11_CKR_OPERATION_NOT_INITIALIZED;
689dc99b202SRuchika Gupta 
690dc99b202SRuchika Gupta 	release_session_find_obj_context(session);
691dc99b202SRuchika Gupta 
692dc99b202SRuchika Gupta 	return PKCS11_CKR_OK;
693dc99b202SRuchika Gupta }
694783c1515SRuchika Gupta 
695e3737878SRuchika Gupta enum pkcs11_rc entry_get_attribute_value(struct pkcs11_client *client,
696783c1515SRuchika Gupta 					 uint32_t ptypes, TEE_Param *params)
697783c1515SRuchika Gupta {
698783c1515SRuchika Gupta 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
699783c1515SRuchika Gupta 						TEE_PARAM_TYPE_NONE,
700783c1515SRuchika Gupta 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
701783c1515SRuchika Gupta 						TEE_PARAM_TYPE_NONE);
702783c1515SRuchika Gupta 	TEE_Param *ctrl = params;
703783c1515SRuchika Gupta 	TEE_Param *out = params + 2;
704783c1515SRuchika Gupta 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
705783c1515SRuchika Gupta 	struct serialargs ctrlargs = { };
706783c1515SRuchika Gupta 	struct pkcs11_session *session = NULL;
707783c1515SRuchika Gupta 	struct pkcs11_object_head *template = NULL;
708783c1515SRuchika Gupta 	struct pkcs11_object *obj = NULL;
709783c1515SRuchika Gupta 	uint32_t object_handle = 0;
710783c1515SRuchika Gupta 	char *cur = NULL;
711783c1515SRuchika Gupta 	size_t len = 0;
712783c1515SRuchika Gupta 	char *end = NULL;
713783c1515SRuchika Gupta 	bool attr_sensitive = 0;
714783c1515SRuchika Gupta 	bool attr_type_invalid = 0;
715783c1515SRuchika Gupta 	bool buffer_too_small = 0;
716783c1515SRuchika Gupta 
717783c1515SRuchika Gupta 	if (!client || ptypes != exp_pt)
718783c1515SRuchika Gupta 		return PKCS11_CKR_ARGUMENTS_BAD;
719783c1515SRuchika Gupta 
720783c1515SRuchika Gupta 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
721783c1515SRuchika Gupta 
722783c1515SRuchika Gupta 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
723783c1515SRuchika Gupta 	if (rc)
724783c1515SRuchika Gupta 		return rc;
725783c1515SRuchika Gupta 
726783c1515SRuchika Gupta 	rc = serialargs_get(&ctrlargs, &object_handle, sizeof(uint32_t));
727783c1515SRuchika Gupta 	if (rc)
728783c1515SRuchika Gupta 		return rc;
729783c1515SRuchika Gupta 
730783c1515SRuchika Gupta 	rc = serialargs_alloc_get_attributes(&ctrlargs, &template);
731783c1515SRuchika Gupta 	if (rc)
732783c1515SRuchika Gupta 		return rc;
733783c1515SRuchika Gupta 
734783c1515SRuchika Gupta 	if (serialargs_remaining_bytes(&ctrlargs)) {
735783c1515SRuchika Gupta 		rc = PKCS11_CKR_ARGUMENTS_BAD;
736783c1515SRuchika Gupta 		goto out;
737783c1515SRuchika Gupta 	}
738783c1515SRuchika Gupta 
739783c1515SRuchika Gupta 	obj = pkcs11_handle2object(object_handle, session);
740783c1515SRuchika Gupta 	if (!obj) {
741783c1515SRuchika Gupta 		rc = PKCS11_CKR_OBJECT_HANDLE_INVALID;
742783c1515SRuchika Gupta 		goto out;
743783c1515SRuchika Gupta 	}
744783c1515SRuchika Gupta 
745783c1515SRuchika Gupta 	rc = check_access_attrs_against_token(session, obj->attributes);
746783c1515SRuchika Gupta 	if (rc) {
747783c1515SRuchika Gupta 		rc = PKCS11_CKR_OBJECT_HANDLE_INVALID;
748783c1515SRuchika Gupta 		goto out;
749783c1515SRuchika Gupta 	}
750783c1515SRuchika Gupta 
751783c1515SRuchika Gupta 	/* Iterate over attributes and set their values */
752783c1515SRuchika Gupta 	/*
753783c1515SRuchika Gupta 	 * 1. If the specified attribute (i.e., the attribute specified by the
754783c1515SRuchika Gupta 	 * type field) for the object cannot be revealed because the object is
755783c1515SRuchika Gupta 	 * sensitive or unextractable, then the ulValueLen field in that triple
756783c1515SRuchika Gupta 	 * is modified to hold the value PKCS11_CK_UNAVAILABLE_INFORMATION.
757783c1515SRuchika Gupta 	 *
758783c1515SRuchika Gupta 	 * 2. Otherwise, if the specified value for the object is invalid (the
759783c1515SRuchika Gupta 	 * object does not possess such an attribute), then the ulValueLen field
760783c1515SRuchika Gupta 	 * in that triple is modified to hold the value
761783c1515SRuchika Gupta 	 * PKCS11_CK_UNAVAILABLE_INFORMATION.
762783c1515SRuchika Gupta 	 *
763783c1515SRuchika Gupta 	 * 3. Otherwise, if the pValue field has the value NULL_PTR, then the
764783c1515SRuchika Gupta 	 * ulValueLen field is modified to hold the exact length of the
765783c1515SRuchika Gupta 	 * specified attribute for the object.
766783c1515SRuchika Gupta 	 *
767783c1515SRuchika Gupta 	 * 4. Otherwise, if the length specified in ulValueLen is large enough
768783c1515SRuchika Gupta 	 * to hold the value of the specified attribute for the object, then
769783c1515SRuchika Gupta 	 * that attribute is copied into the buffer located at pValue, and the
770783c1515SRuchika Gupta 	 * ulValueLen field is modified to hold the exact length of the
771783c1515SRuchika Gupta 	 * attribute.
772783c1515SRuchika Gupta 	 *
773783c1515SRuchika Gupta 	 * 5. Otherwise, the ulValueLen field is modified to hold the value
774783c1515SRuchika Gupta 	 * PKCS11_CK_UNAVAILABLE_INFORMATION.
775783c1515SRuchika Gupta 	 */
776783c1515SRuchika Gupta 	cur = (char *)template + sizeof(struct pkcs11_object_head);
777783c1515SRuchika Gupta 	end = cur + template->attrs_size;
778783c1515SRuchika Gupta 
779783c1515SRuchika Gupta 	for (; cur < end; cur += len) {
780783c1515SRuchika Gupta 		struct pkcs11_attribute_head *cli_ref = (void *)cur;
78118cbc7a2SVesa Jääskeläinen 		struct pkcs11_attribute_head cli_head = { };
78218cbc7a2SVesa Jääskeläinen 		void *data_ptr = NULL;
783783c1515SRuchika Gupta 
78418cbc7a2SVesa Jääskeläinen 		/* Make copy of header so that is aligned properly. */
78518cbc7a2SVesa Jääskeläinen 		TEE_MemMove(&cli_head, cli_ref, sizeof(cli_head));
78618cbc7a2SVesa Jääskeläinen 
78718cbc7a2SVesa Jääskeläinen 		len = sizeof(*cli_ref) + cli_head.size;
788783c1515SRuchika Gupta 
789783c1515SRuchika Gupta 		/* Check 1. */
79018cbc7a2SVesa Jääskeläinen 		if (!attribute_is_exportable(&cli_head, obj)) {
79118cbc7a2SVesa Jääskeläinen 			cli_head.size = PKCS11_CK_UNAVAILABLE_INFORMATION;
79218cbc7a2SVesa Jääskeläinen 			TEE_MemMove(&cli_ref->size, &cli_head.size,
79318cbc7a2SVesa Jääskeläinen 				    sizeof(cli_head.size));
794783c1515SRuchika Gupta 			attr_sensitive = 1;
795783c1515SRuchika Gupta 			continue;
796783c1515SRuchika Gupta 		}
797783c1515SRuchika Gupta 
79818cbc7a2SVesa Jääskeläinen 		/* Get real data pointer from template data */
799f3178382SVesa Jääskeläinen 		data_ptr = cli_head.size ? cli_ref->data : NULL;
80018cbc7a2SVesa Jääskeläinen 
801783c1515SRuchika Gupta 		/*
802783c1515SRuchika Gupta 		 * We assume that if size is 0, pValue was NULL, so we return
803783c1515SRuchika Gupta 		 * the size of the required buffer for it (3., 4.)
804783c1515SRuchika Gupta 		 */
805f3178382SVesa Jääskeläinen 		rc = get_attribute(obj->attributes, cli_head.id, data_ptr,
80618cbc7a2SVesa Jääskeläinen 				   &cli_head.size);
807783c1515SRuchika Gupta 		/* Check 2. */
808783c1515SRuchika Gupta 		switch (rc) {
809783c1515SRuchika Gupta 		case PKCS11_CKR_OK:
810783c1515SRuchika Gupta 			break;
811783c1515SRuchika Gupta 		case PKCS11_RV_NOT_FOUND:
81218cbc7a2SVesa Jääskeläinen 			cli_head.size = PKCS11_CK_UNAVAILABLE_INFORMATION;
813783c1515SRuchika Gupta 			attr_type_invalid = 1;
814783c1515SRuchika Gupta 			break;
815783c1515SRuchika Gupta 		case PKCS11_CKR_BUFFER_TOO_SMALL:
816f3178382SVesa Jääskeläinen 			if (data_ptr)
817783c1515SRuchika Gupta 				buffer_too_small = 1;
818783c1515SRuchika Gupta 			break;
819783c1515SRuchika Gupta 		default:
820783c1515SRuchika Gupta 			rc = PKCS11_CKR_GENERAL_ERROR;
821783c1515SRuchika Gupta 			goto out;
822783c1515SRuchika Gupta 		}
82318cbc7a2SVesa Jääskeläinen 
82418cbc7a2SVesa Jääskeläinen 		TEE_MemMove(&cli_ref->size, &cli_head.size,
82518cbc7a2SVesa Jääskeläinen 			    sizeof(cli_head.size));
826783c1515SRuchika Gupta 	}
827783c1515SRuchika Gupta 
828783c1515SRuchika Gupta 	/*
829783c1515SRuchika Gupta 	 * If case 1 applies to any of the requested attributes, then the call
830783c1515SRuchika Gupta 	 * should return the value CKR_ATTRIBUTE_SENSITIVE. If case 2 applies to
831783c1515SRuchika Gupta 	 * any of the requested attributes, then the call should return the
832783c1515SRuchika Gupta 	 * value CKR_ATTRIBUTE_TYPE_INVALID. If case 5 applies to any of the
833783c1515SRuchika Gupta 	 * requested attributes, then the call should return the value
834783c1515SRuchika Gupta 	 * CKR_BUFFER_TOO_SMALL. As usual, if more than one of these error codes
835783c1515SRuchika Gupta 	 * is applicable, Cryptoki may return any of them. Only if none of them
836783c1515SRuchika Gupta 	 * applies to any of the requested attributes will CKR_OK be returned.
837783c1515SRuchika Gupta 	 */
838783c1515SRuchika Gupta 
839783c1515SRuchika Gupta 	rc = PKCS11_CKR_OK;
840783c1515SRuchika Gupta 	if (attr_sensitive)
841783c1515SRuchika Gupta 		rc = PKCS11_CKR_ATTRIBUTE_SENSITIVE;
842783c1515SRuchika Gupta 	if (attr_type_invalid)
843783c1515SRuchika Gupta 		rc = PKCS11_CKR_ATTRIBUTE_TYPE_INVALID;
844783c1515SRuchika Gupta 	if (buffer_too_small)
845783c1515SRuchika Gupta 		rc = PKCS11_CKR_BUFFER_TOO_SMALL;
846783c1515SRuchika Gupta 
847783c1515SRuchika Gupta 	/* Move updated template to out buffer */
848783c1515SRuchika Gupta 	TEE_MemMove(out->memref.buffer, template, out->memref.size);
849783c1515SRuchika Gupta 
850783c1515SRuchika Gupta 	DMSG("PKCS11 session %"PRIu32": get attributes %#"PRIx32,
851783c1515SRuchika Gupta 	     session->handle, object_handle);
852783c1515SRuchika Gupta 
853783c1515SRuchika Gupta out:
854783c1515SRuchika Gupta 	TEE_Free(template);
855783c1515SRuchika Gupta 
856783c1515SRuchika Gupta 	return rc;
857783c1515SRuchika Gupta }
858783c1515SRuchika Gupta 
859e3737878SRuchika Gupta enum pkcs11_rc entry_get_object_size(struct pkcs11_client *client,
860783c1515SRuchika Gupta 				     uint32_t ptypes, TEE_Param *params)
861783c1515SRuchika Gupta {
862783c1515SRuchika Gupta 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
863783c1515SRuchika Gupta 						TEE_PARAM_TYPE_NONE,
864783c1515SRuchika Gupta 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
865783c1515SRuchika Gupta 						TEE_PARAM_TYPE_NONE);
866783c1515SRuchika Gupta 	TEE_Param *ctrl = params;
867783c1515SRuchika Gupta 	TEE_Param *out = params + 2;
868783c1515SRuchika Gupta 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
869783c1515SRuchika Gupta 	struct serialargs ctrlargs = { };
870783c1515SRuchika Gupta 	struct pkcs11_session *session = NULL;
871783c1515SRuchika Gupta 	uint32_t object_handle = 0;
872783c1515SRuchika Gupta 	struct pkcs11_object *obj = NULL;
873783c1515SRuchika Gupta 	uint32_t obj_size = 0;
874783c1515SRuchika Gupta 
875783c1515SRuchika Gupta 	if (!client || ptypes != exp_pt)
876783c1515SRuchika Gupta 		return PKCS11_CKR_ARGUMENTS_BAD;
877783c1515SRuchika Gupta 
878783c1515SRuchika Gupta 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
879783c1515SRuchika Gupta 
880783c1515SRuchika Gupta 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
881783c1515SRuchika Gupta 	if (rc)
882783c1515SRuchika Gupta 		return rc;
883783c1515SRuchika Gupta 
884783c1515SRuchika Gupta 	rc = serialargs_get(&ctrlargs, &object_handle, sizeof(uint32_t));
885783c1515SRuchika Gupta 	if (rc)
886783c1515SRuchika Gupta 		return rc;
887783c1515SRuchika Gupta 
888783c1515SRuchika Gupta 	if (serialargs_remaining_bytes(&ctrlargs))
889783c1515SRuchika Gupta 		return PKCS11_CKR_ARGUMENTS_BAD;
890783c1515SRuchika Gupta 
891783c1515SRuchika Gupta 	obj = pkcs11_handle2object(object_handle, session);
892783c1515SRuchika Gupta 	if (!obj)
893783c1515SRuchika Gupta 		return PKCS11_CKR_OBJECT_HANDLE_INVALID;
894783c1515SRuchika Gupta 
895783c1515SRuchika Gupta 	rc = check_access_attrs_against_token(session, obj->attributes);
896783c1515SRuchika Gupta 	if (rc)
897783c1515SRuchika Gupta 		return PKCS11_CKR_OBJECT_HANDLE_INVALID;
898783c1515SRuchika Gupta 
899783c1515SRuchika Gupta 	if (out->memref.size != sizeof(uint32_t))
900783c1515SRuchika Gupta 		return PKCS11_CKR_ARGUMENTS_BAD;
901783c1515SRuchika Gupta 
902783c1515SRuchika Gupta 	obj_size = ((struct obj_attrs *)obj->attributes)->attrs_size +
903783c1515SRuchika Gupta 		   sizeof(struct obj_attrs);
904783c1515SRuchika Gupta 	TEE_MemMove(out->memref.buffer, &obj_size, sizeof(obj_size));
905783c1515SRuchika Gupta 
906783c1515SRuchika Gupta 	return PKCS11_CKR_OK;
907783c1515SRuchika Gupta }
9082d25a9bcSRuchika Gupta 
9092d25a9bcSRuchika Gupta enum pkcs11_rc entry_set_attribute_value(struct pkcs11_client *client,
9102d25a9bcSRuchika Gupta 					 uint32_t ptypes, TEE_Param *params)
9112d25a9bcSRuchika Gupta {
9122d25a9bcSRuchika Gupta 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
9132d25a9bcSRuchika Gupta 						TEE_PARAM_TYPE_NONE,
9142d25a9bcSRuchika Gupta 						TEE_PARAM_TYPE_NONE,
9152d25a9bcSRuchika Gupta 						TEE_PARAM_TYPE_NONE);
9162d25a9bcSRuchika Gupta 	TEE_Param *ctrl = params;
9172d25a9bcSRuchika Gupta 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
9182d25a9bcSRuchika Gupta 	struct serialargs ctrlargs = { };
9192d25a9bcSRuchika Gupta 	struct pkcs11_session *session = NULL;
9202d25a9bcSRuchika Gupta 	struct pkcs11_object_head *template = NULL;
9212d25a9bcSRuchika Gupta 	size_t template_size = 0;
9222d25a9bcSRuchika Gupta 	struct pkcs11_object *obj = NULL;
9232d25a9bcSRuchika Gupta 	struct obj_attrs *head = NULL;
9242d25a9bcSRuchika Gupta 	uint32_t object_handle = 0;
9252d25a9bcSRuchika Gupta 	enum processing_func function = PKCS11_FUNCTION_MODIFY;
9262d25a9bcSRuchika Gupta 
9272d25a9bcSRuchika Gupta 	if (!client || ptypes != exp_pt)
9282d25a9bcSRuchika Gupta 		return PKCS11_CKR_ARGUMENTS_BAD;
9292d25a9bcSRuchika Gupta 
9302d25a9bcSRuchika Gupta 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
9312d25a9bcSRuchika Gupta 
9322d25a9bcSRuchika Gupta 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
9332d25a9bcSRuchika Gupta 	if (rc)
9342d25a9bcSRuchika Gupta 		return rc;
9352d25a9bcSRuchika Gupta 
9362d25a9bcSRuchika Gupta 	rc = serialargs_get(&ctrlargs, &object_handle, sizeof(uint32_t));
9372d25a9bcSRuchika Gupta 	if (rc)
9382d25a9bcSRuchika Gupta 		return rc;
9392d25a9bcSRuchika Gupta 
9402d25a9bcSRuchika Gupta 	rc = serialargs_alloc_get_attributes(&ctrlargs, &template);
9412d25a9bcSRuchika Gupta 	if (rc)
9422d25a9bcSRuchika Gupta 		return rc;
9432d25a9bcSRuchika Gupta 
9442d25a9bcSRuchika Gupta 	if (serialargs_remaining_bytes(&ctrlargs)) {
9452d25a9bcSRuchika Gupta 		rc = PKCS11_CKR_ARGUMENTS_BAD;
9462d25a9bcSRuchika Gupta 		goto out;
9472d25a9bcSRuchika Gupta 	}
9482d25a9bcSRuchika Gupta 
9492d25a9bcSRuchika Gupta 	obj = pkcs11_handle2object(object_handle, session);
9502d25a9bcSRuchika Gupta 	if (!obj) {
9512d25a9bcSRuchika Gupta 		rc = PKCS11_CKR_OBJECT_HANDLE_INVALID;
9522d25a9bcSRuchika Gupta 		goto out;
9532d25a9bcSRuchika Gupta 	}
9542d25a9bcSRuchika Gupta 
9552d25a9bcSRuchika Gupta 	/* Only session objects can be modified during a read-only session */
9562d25a9bcSRuchika Gupta 	if (object_is_token(obj->attributes) &&
9572d25a9bcSRuchika Gupta 	    !pkcs11_session_is_read_write(session)) {
9582d25a9bcSRuchika Gupta 		DMSG("Can't modify persistent object in a RO session");
9592d25a9bcSRuchika Gupta 		rc = PKCS11_CKR_SESSION_READ_ONLY;
9602d25a9bcSRuchika Gupta 		goto out;
9612d25a9bcSRuchika Gupta 	}
9622d25a9bcSRuchika Gupta 
9632d25a9bcSRuchika Gupta 	/*
9642d25a9bcSRuchika Gupta 	 * Only public objects can be modified unless normal user is logged in
9652d25a9bcSRuchika Gupta 	 */
9662d25a9bcSRuchika Gupta 	rc = check_access_attrs_against_token(session, obj->attributes);
9672d25a9bcSRuchika Gupta 	if (rc) {
9682d25a9bcSRuchika Gupta 		rc = PKCS11_CKR_USER_NOT_LOGGED_IN;
9692d25a9bcSRuchika Gupta 		goto out;
9702d25a9bcSRuchika Gupta 	}
9712d25a9bcSRuchika Gupta 
9722d25a9bcSRuchika Gupta 	/* Objects with PKCS11_CKA_MODIFIABLE as false aren't modifiable */
9732d25a9bcSRuchika Gupta 	if (!object_is_modifiable(obj->attributes)) {
9742d25a9bcSRuchika Gupta 		rc = PKCS11_CKR_ACTION_PROHIBITED;
9752d25a9bcSRuchika Gupta 		goto out;
9762d25a9bcSRuchika Gupta 	}
9772d25a9bcSRuchika Gupta 
9782d25a9bcSRuchika Gupta 	template_size = sizeof(*template) + template->attrs_size;
9792d25a9bcSRuchika Gupta 
9802d25a9bcSRuchika Gupta 	/*
9812d25a9bcSRuchika Gupta 	 * Prepare a clean initial state (@head) for the template. Helps in
9822d25a9bcSRuchika Gupta 	 * removing any duplicates or inconsistent values from the
9832d25a9bcSRuchika Gupta 	 * template.
9842d25a9bcSRuchika Gupta 	 */
9852d25a9bcSRuchika Gupta 	rc = create_attributes_from_template(&head, template, template_size,
9862d25a9bcSRuchika Gupta 					     NULL, function,
9872d25a9bcSRuchika Gupta 					     PKCS11_CKM_UNDEFINED_ID,
9882d25a9bcSRuchika Gupta 					     PKCS11_CKO_UNDEFINED_ID);
9892d25a9bcSRuchika Gupta 	if (rc)
9902d25a9bcSRuchika Gupta 		goto out;
9912d25a9bcSRuchika Gupta 
9922d25a9bcSRuchika Gupta 	/* Check the attributes in @head to see if they are modifiable */
9932d25a9bcSRuchika Gupta 	rc = check_attrs_against_modification(session, head, obj, function);
9942d25a9bcSRuchika Gupta 	if (rc)
9952d25a9bcSRuchika Gupta 		goto out;
9962d25a9bcSRuchika Gupta 
9972d25a9bcSRuchika Gupta 	/*
9982d25a9bcSRuchika Gupta 	 * All checks complete. The attributes in @head have been checked and
9992d25a9bcSRuchika Gupta 	 * can now be used to set/modify the object attributes.
10002d25a9bcSRuchika Gupta 	 */
10012d25a9bcSRuchika Gupta 	rc = modify_attributes_list(&obj->attributes, head);
10022d25a9bcSRuchika Gupta 	if (rc)
10032d25a9bcSRuchika Gupta 		goto out;
10042d25a9bcSRuchika Gupta 
1005*402d884aSRuchika Gupta 	if (get_bool(obj->attributes, PKCS11_CKA_TOKEN)) {
1006*402d884aSRuchika Gupta 		rc = update_persistent_object_attributes(obj);
1007*402d884aSRuchika Gupta 		if (rc)
1008*402d884aSRuchika Gupta 			goto out;
1009*402d884aSRuchika Gupta 	}
1010*402d884aSRuchika Gupta 
10112d25a9bcSRuchika Gupta 	DMSG("PKCS11 session %"PRIu32": set attributes %#"PRIx32,
10122d25a9bcSRuchika Gupta 	     session->handle, object_handle);
10132d25a9bcSRuchika Gupta 
10142d25a9bcSRuchika Gupta out:
10152d25a9bcSRuchika Gupta 	TEE_Free(head);
10162d25a9bcSRuchika Gupta 	TEE_Free(template);
10172d25a9bcSRuchika Gupta 	return rc;
10182d25a9bcSRuchika Gupta }
1019bc09507cSRuchika Gupta 
1020bc09507cSRuchika Gupta enum pkcs11_rc entry_copy_object(struct pkcs11_client *client, uint32_t ptypes,
1021bc09507cSRuchika Gupta 				 TEE_Param *params)
1022bc09507cSRuchika Gupta {
1023bc09507cSRuchika Gupta 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
1024bc09507cSRuchika Gupta 						TEE_PARAM_TYPE_NONE,
1025bc09507cSRuchika Gupta 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
1026bc09507cSRuchika Gupta 						TEE_PARAM_TYPE_NONE);
1027bc09507cSRuchika Gupta 	TEE_Param *ctrl = params;
1028bc09507cSRuchika Gupta 	TEE_Param *out = params + 2;
1029bc09507cSRuchika Gupta 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
1030bc09507cSRuchika Gupta 	struct serialargs ctrlargs = { };
1031bc09507cSRuchika Gupta 	struct pkcs11_session *session = NULL;
1032bc09507cSRuchika Gupta 	struct pkcs11_object_head *template = NULL;
1033bc09507cSRuchika Gupta 	struct obj_attrs *head = NULL;
1034bc09507cSRuchika Gupta 	struct obj_attrs *head_new = NULL;
1035bc09507cSRuchika Gupta 	size_t template_size = 0;
1036bc09507cSRuchika Gupta 	struct pkcs11_object *obj = NULL;
1037bc09507cSRuchika Gupta 	uint32_t object_handle = 0;
1038bc09507cSRuchika Gupta 	uint32_t obj_handle = 0;
1039bc09507cSRuchika Gupta 	enum processing_func function = PKCS11_FUNCTION_COPY;
1040bc09507cSRuchika Gupta 	enum pkcs11_class_id class = PKCS11_CKO_UNDEFINED_ID;
1041bc09507cSRuchika Gupta 
1042bc09507cSRuchika Gupta 	if (!client || ptypes != exp_pt ||
1043bc09507cSRuchika Gupta 	    out->memref.size != sizeof(obj_handle))
1044bc09507cSRuchika Gupta 		return PKCS11_CKR_ARGUMENTS_BAD;
1045bc09507cSRuchika Gupta 
1046bc09507cSRuchika Gupta 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
1047bc09507cSRuchika Gupta 
1048bc09507cSRuchika Gupta 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
1049bc09507cSRuchika Gupta 	if (rc)
1050bc09507cSRuchika Gupta 		return rc;
1051bc09507cSRuchika Gupta 
1052bc09507cSRuchika Gupta 	rc = serialargs_get(&ctrlargs, &object_handle, sizeof(uint32_t));
1053bc09507cSRuchika Gupta 	if (rc)
1054bc09507cSRuchika Gupta 		return rc;
1055bc09507cSRuchika Gupta 
1056bc09507cSRuchika Gupta 	rc = serialargs_alloc_get_attributes(&ctrlargs, &template);
1057bc09507cSRuchika Gupta 	if (rc)
1058bc09507cSRuchika Gupta 		return rc;
1059bc09507cSRuchika Gupta 
1060bc09507cSRuchika Gupta 	if (serialargs_remaining_bytes(&ctrlargs)) {
1061bc09507cSRuchika Gupta 		rc = PKCS11_CKR_ARGUMENTS_BAD;
1062bc09507cSRuchika Gupta 		goto out;
1063bc09507cSRuchika Gupta 	}
1064bc09507cSRuchika Gupta 
1065bc09507cSRuchika Gupta 	obj = pkcs11_handle2object(object_handle, session);
1066bc09507cSRuchika Gupta 	if (!obj) {
1067bc09507cSRuchika Gupta 		rc = PKCS11_CKR_OBJECT_HANDLE_INVALID;
1068bc09507cSRuchika Gupta 		goto out;
1069bc09507cSRuchika Gupta 	}
1070bc09507cSRuchika Gupta 
1071bc09507cSRuchika Gupta 	/* Only session objects can be modified during a read-only session */
1072bc09507cSRuchika Gupta 	if (object_is_token(obj->attributes) &&
1073bc09507cSRuchika Gupta 	    !pkcs11_session_is_read_write(session)) {
1074bc09507cSRuchika Gupta 		DMSG("Can't modify persistent object in a RO session");
1075bc09507cSRuchika Gupta 		rc = PKCS11_CKR_SESSION_READ_ONLY;
1076bc09507cSRuchika Gupta 		goto out;
1077bc09507cSRuchika Gupta 	}
1078bc09507cSRuchika Gupta 
1079bc09507cSRuchika Gupta 	/*
1080bc09507cSRuchika Gupta 	 * Only public objects can be modified unless normal user is logged in
1081bc09507cSRuchika Gupta 	 */
1082bc09507cSRuchika Gupta 	rc = check_access_attrs_against_token(session, obj->attributes);
1083bc09507cSRuchika Gupta 	if (rc) {
1084bc09507cSRuchika Gupta 		rc = PKCS11_CKR_USER_NOT_LOGGED_IN;
1085bc09507cSRuchika Gupta 		goto out;
1086bc09507cSRuchika Gupta 	}
1087bc09507cSRuchika Gupta 
1088bc09507cSRuchika Gupta 	/* Objects with PKCS11_CKA_COPYABLE as false can't be copied */
1089bc09507cSRuchika Gupta 	if (!object_is_copyable(obj->attributes)) {
1090bc09507cSRuchika Gupta 		rc = PKCS11_CKR_ACTION_PROHIBITED;
1091bc09507cSRuchika Gupta 		goto out;
1092bc09507cSRuchika Gupta 	}
1093bc09507cSRuchika Gupta 
1094bc09507cSRuchika Gupta 	template_size = sizeof(*template) + template->attrs_size;
1095bc09507cSRuchika Gupta 
1096bc09507cSRuchika Gupta 	/*
1097bc09507cSRuchika Gupta 	 * Prepare a clean initial state (@head) for the template. Helps in
1098bc09507cSRuchika Gupta 	 * removing any duplicates or inconsistent values from the
1099bc09507cSRuchika Gupta 	 * template.
1100bc09507cSRuchika Gupta 	 */
1101bc09507cSRuchika Gupta 	rc = create_attributes_from_template(&head, template, template_size,
1102bc09507cSRuchika Gupta 					     NULL, function,
1103bc09507cSRuchika Gupta 					     PKCS11_CKM_UNDEFINED_ID,
1104bc09507cSRuchika Gupta 					     PKCS11_CKO_UNDEFINED_ID);
1105bc09507cSRuchika Gupta 	if (rc)
1106bc09507cSRuchika Gupta 		goto out;
1107bc09507cSRuchika Gupta 
1108bc09507cSRuchika Gupta 	/* Check the attributes in @head to see if they are modifiable */
1109bc09507cSRuchika Gupta 	rc = check_attrs_against_modification(session, head, obj, function);
1110bc09507cSRuchika Gupta 	if (rc)
1111bc09507cSRuchika Gupta 		goto out;
1112bc09507cSRuchika Gupta 
1113bc09507cSRuchika Gupta 	class = get_class(obj->attributes);
1114bc09507cSRuchika Gupta 
1115bc09507cSRuchika Gupta 	if (class == PKCS11_CKO_SECRET_KEY ||
1116bc09507cSRuchika Gupta 	    class == PKCS11_CKO_PRIVATE_KEY) {
1117bc09507cSRuchika Gupta 		/*
1118bc09507cSRuchika Gupta 		 * If CKA_EXTRACTABLE attribute in passed template (@head) is
1119bc09507cSRuchika Gupta 		 * modified to CKA_FALSE, CKA_NEVER_EXTRACTABLE should also
1120bc09507cSRuchika Gupta 		 * change to CKA_FALSE in copied obj. So, add it to the
1121bc09507cSRuchika Gupta 		 * passed template.
1122bc09507cSRuchika Gupta 		 */
1123bc09507cSRuchika Gupta 		uint8_t bbool = 0;
1124bc09507cSRuchika Gupta 		uint32_t size = sizeof(bbool);
1125bc09507cSRuchika Gupta 
1126bc09507cSRuchika Gupta 		rc = get_attribute(head, PKCS11_CKA_EXTRACTABLE, &bbool, &size);
1127bc09507cSRuchika Gupta 		if (!rc && !bbool) {
1128bc09507cSRuchika Gupta 			rc = add_attribute(&head, PKCS11_CKA_NEVER_EXTRACTABLE,
1129bc09507cSRuchika Gupta 					   &bbool, sizeof(uint8_t));
1130bc09507cSRuchika Gupta 			if (rc)
1131bc09507cSRuchika Gupta 				goto out;
1132bc09507cSRuchika Gupta 		}
1133bc09507cSRuchika Gupta 		rc = PKCS11_CKR_OK;
1134bc09507cSRuchika Gupta 	}
1135bc09507cSRuchika Gupta 
1136bc09507cSRuchika Gupta 	/*
1137bc09507cSRuchika Gupta 	 * All checks have passed. Create a copy of the serialized buffer which
1138bc09507cSRuchika Gupta 	 * holds the object attributes in @head_new for the new object
1139bc09507cSRuchika Gupta 	 */
1140bc09507cSRuchika Gupta 	template_size = sizeof(*obj->attributes) + obj->attributes->attrs_size;
1141bc09507cSRuchika Gupta 	head_new = TEE_Malloc(template_size, TEE_MALLOC_FILL_ZERO);
1142bc09507cSRuchika Gupta 	if (!head_new) {
1143bc09507cSRuchika Gupta 		rc = PKCS11_CKR_DEVICE_MEMORY;
1144bc09507cSRuchika Gupta 		goto out;
1145bc09507cSRuchika Gupta 	}
1146bc09507cSRuchika Gupta 
1147bc09507cSRuchika Gupta 	TEE_MemMove(head_new, obj->attributes, template_size);
1148bc09507cSRuchika Gupta 
1149bc09507cSRuchika Gupta 	/*
1150bc09507cSRuchika Gupta 	 * Modify the copied attribute @head_new based on the template @head
1151bc09507cSRuchika Gupta 	 * given by the callee
1152bc09507cSRuchika Gupta 	 */
1153bc09507cSRuchika Gupta 	rc = modify_attributes_list(&head_new, head);
1154bc09507cSRuchika Gupta 	if (rc)
1155bc09507cSRuchika Gupta 		goto out;
1156bc09507cSRuchika Gupta 
1157bc09507cSRuchika Gupta 	/*
1158bc09507cSRuchika Gupta 	 * At this stage the object is almost created: all its attributes are
1159bc09507cSRuchika Gupta 	 * referenced in @head_new, including the key value and are assumed
1160bc09507cSRuchika Gupta 	 * reliable. Now need to register it and get a handle for it.
1161bc09507cSRuchika Gupta 	 */
1162bc09507cSRuchika Gupta 	rc = create_object(session, head_new, &obj_handle);
1163bc09507cSRuchika Gupta 	if (rc)
1164bc09507cSRuchika Gupta 		goto out;
1165bc09507cSRuchika Gupta 
1166bc09507cSRuchika Gupta 	/*
1167bc09507cSRuchika Gupta 	 * Now obj_handle (through the related struct pkcs11_object
1168e3737878SRuchika Gupta 	 * instance) owns the serialized buffer that holds the object
1169bc09507cSRuchika Gupta 	 * attributes. We clear reference in head to NULL as the serializer
1170bc09507cSRuchika Gupta 	 * object is now referred from obj_handle. This allows smooth pass
1171bc09507cSRuchika Gupta 	 * through free at function exit.
1172bc09507cSRuchika Gupta 	 */
1173bc09507cSRuchika Gupta 	head_new = NULL;
1174bc09507cSRuchika Gupta 
1175bc09507cSRuchika Gupta 	TEE_MemMove(out->memref.buffer, &obj_handle, sizeof(obj_handle));
1176bc09507cSRuchika Gupta 	out->memref.size = sizeof(obj_handle);
1177bc09507cSRuchika Gupta 
1178bc09507cSRuchika Gupta 	DMSG("PKCS11 session %"PRIu32": copy object %#"PRIx32,
1179bc09507cSRuchika Gupta 	     session->handle, obj_handle);
1180bc09507cSRuchika Gupta 
1181bc09507cSRuchika Gupta out:
1182bc09507cSRuchika Gupta 	TEE_Free(head_new);
1183bc09507cSRuchika Gupta 	TEE_Free(head);
1184bc09507cSRuchika Gupta 	TEE_Free(template);
1185bc09507cSRuchika Gupta 	return rc;
1186bc09507cSRuchika Gupta }
1187