xref: /optee_os/ta/pkcs11/src/object.c (revision b79640377e181dba4ada0a5e1ec986bb1a2bbfb2)
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 
2102dbcc7eSEtienne Carriere /*
2202dbcc7eSEtienne Carriere  * Temporary list used to register allocated struct pkcs11_object instances
2302dbcc7eSEtienne Carriere  * so that destroy_object() can unconditionally remove the object from its
2402dbcc7eSEtienne Carriere  * list, being from an object destruction request or because object creation
2502dbcc7eSEtienne Carriere  * failed before being completed. Objects are moved to their target list at
2602dbcc7eSEtienne Carriere  * creation completion.
2702dbcc7eSEtienne Carriere  */
2802dbcc7eSEtienne Carriere LIST_HEAD(temp_obj_list, pkcs11_object) temporary_object_list =
2902dbcc7eSEtienne Carriere 	LIST_HEAD_INITIALIZER(temp_obj_list);
3002dbcc7eSEtienne Carriere 
31bc555ee0SVesa Jääskeläinen static struct ck_token *get_session_token(void *session);
32bc555ee0SVesa Jääskeläinen 
33b56b3d07SJens Wiklander struct pkcs11_object *pkcs11_handle2object(uint32_t handle,
34b56b3d07SJens Wiklander 					   struct pkcs11_session *session)
35b56b3d07SJens Wiklander {
36bc555ee0SVesa Jääskeläinen 	struct pkcs11_object *object = NULL;
37bc555ee0SVesa Jääskeläinen 
38bc555ee0SVesa Jääskeläinen 	object = handle_lookup(get_object_handle_db(session), handle);
39bc555ee0SVesa Jääskeläinen 	if (!object)
40bc555ee0SVesa Jääskeläinen 		return NULL;
41bc555ee0SVesa Jääskeläinen 
42bc555ee0SVesa Jääskeläinen 	/*
43bc555ee0SVesa Jääskeläinen 	 * If object is session only then no extra checks are needed as session
44bc555ee0SVesa Jääskeläinen 	 * objects has flat access control space
45bc555ee0SVesa Jääskeläinen 	 */
46bc555ee0SVesa Jääskeläinen 	if (!object->token)
47bc555ee0SVesa Jääskeläinen 		return object;
48bc555ee0SVesa Jääskeläinen 
49bc555ee0SVesa Jääskeläinen 	/*
50bc555ee0SVesa Jääskeläinen 	 * Only allow access to token object if session is associated with
51bc555ee0SVesa Jääskeläinen 	 * the token
52bc555ee0SVesa Jääskeläinen 	 */
53bc555ee0SVesa Jääskeläinen 	if (object->token != get_session_token(session))
54bc555ee0SVesa Jääskeläinen 		return NULL;
55bc555ee0SVesa Jääskeläinen 
56bc555ee0SVesa Jääskeläinen 	return object;
57b56b3d07SJens Wiklander }
58b56b3d07SJens Wiklander 
59b56b3d07SJens Wiklander uint32_t pkcs11_object2handle(struct pkcs11_object *obj,
60b56b3d07SJens Wiklander 			      struct pkcs11_session *session)
61b56b3d07SJens Wiklander {
62bc555ee0SVesa Jääskeläinen 	return handle_lookup_handle(get_object_handle_db(session), obj);
63b56b3d07SJens Wiklander }
64b56b3d07SJens Wiklander 
65b56b3d07SJens Wiklander /* Currently handle pkcs11 sessions and tokens */
66b56b3d07SJens Wiklander 
67b56b3d07SJens Wiklander static struct object_list *get_session_objects(void *session)
68b56b3d07SJens Wiklander {
69b56b3d07SJens Wiklander 	/* Currently supporting only pkcs11 session */
70b56b3d07SJens Wiklander 	struct pkcs11_session *ck_session = session;
71b56b3d07SJens Wiklander 
72b56b3d07SJens Wiklander 	return pkcs11_get_session_objects(ck_session);
73b56b3d07SJens Wiklander }
74b56b3d07SJens Wiklander 
75334316feSJens Wiklander static struct ck_token *get_session_token(void *session)
76334316feSJens Wiklander {
77334316feSJens Wiklander 	struct pkcs11_session *ck_session = session;
78334316feSJens Wiklander 
79334316feSJens Wiklander 	return pkcs11_session2token(ck_session);
80334316feSJens Wiklander }
81334316feSJens Wiklander 
82b56b3d07SJens Wiklander /* Release resources of a non-persistent object */
83b56b3d07SJens Wiklander static void cleanup_volatile_obj_ref(struct pkcs11_object *obj)
84b56b3d07SJens Wiklander {
85b56b3d07SJens Wiklander 	if (!obj)
86b56b3d07SJens Wiklander 		return;
87b56b3d07SJens Wiklander 
88b56b3d07SJens Wiklander 	if (obj->key_handle != TEE_HANDLE_NULL)
89b56b3d07SJens Wiklander 		TEE_FreeTransientObject(obj->key_handle);
90b56b3d07SJens Wiklander 
91b56b3d07SJens Wiklander 	if (obj->attribs_hdl != TEE_HANDLE_NULL)
92b56b3d07SJens Wiklander 		TEE_CloseObject(obj->attribs_hdl);
93b56b3d07SJens Wiklander 
94b56b3d07SJens Wiklander 	TEE_Free(obj->attributes);
95b56b3d07SJens Wiklander 	TEE_Free(obj->uuid);
96b56b3d07SJens Wiklander 	TEE_Free(obj);
97b56b3d07SJens Wiklander }
98b56b3d07SJens Wiklander 
99b56b3d07SJens Wiklander /* Release resources of a persistent object including volatile resources */
1007f12c782SRobin van der Gracht void cleanup_persistent_object(struct pkcs11_object *obj,
101334316feSJens Wiklander 			       struct ck_token *token)
102b56b3d07SJens Wiklander {
103334316feSJens Wiklander 	TEE_Result res = TEE_SUCCESS;
104334316feSJens Wiklander 
105334316feSJens Wiklander 	if (!obj)
106334316feSJens Wiklander 		return;
107334316feSJens Wiklander 
108334316feSJens Wiklander 	/* Open handle with write properties to destroy the object */
109334316feSJens Wiklander 	if (obj->attribs_hdl != TEE_HANDLE_NULL)
110334316feSJens Wiklander 		TEE_CloseObject(obj->attribs_hdl);
111334316feSJens Wiklander 
112334316feSJens Wiklander 	res = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE,
113334316feSJens Wiklander 				       obj->uuid, sizeof(TEE_UUID),
114334316feSJens Wiklander 				       TEE_DATA_FLAG_ACCESS_WRITE_META,
115334316feSJens Wiklander 				       &obj->attribs_hdl);
116334316feSJens Wiklander 	if (!res)
117334316feSJens Wiklander 		TEE_CloseAndDeletePersistentObject1(obj->attribs_hdl);
118334316feSJens Wiklander 
119334316feSJens Wiklander 	obj->attribs_hdl = TEE_HANDLE_NULL;
120334316feSJens Wiklander 	destroy_object_uuid(token, obj);
121334316feSJens Wiklander 
122334316feSJens Wiklander 	LIST_REMOVE(obj, link);
123334316feSJens Wiklander 
124334316feSJens Wiklander 	cleanup_volatile_obj_ref(obj);
125b56b3d07SJens Wiklander }
126b56b3d07SJens Wiklander 
127b56b3d07SJens Wiklander /*
128b56b3d07SJens Wiklander  * destroy_object - destroy an PKCS11 TA object
129b56b3d07SJens Wiklander  *
130b56b3d07SJens Wiklander  * @session - session requesting object destruction
131b56b3d07SJens Wiklander  * @obj - reference to the PKCS11 TA object
132b56b3d07SJens Wiklander  * @session_only - true if only session object shall be destroyed
133b56b3d07SJens Wiklander  */
134b56b3d07SJens Wiklander void destroy_object(struct pkcs11_session *session, struct pkcs11_object *obj,
135b56b3d07SJens Wiklander 		    bool session_only)
136b56b3d07SJens Wiklander {
137b56b3d07SJens Wiklander #ifdef DEBUG
138b56b3d07SJens Wiklander 	trace_attributes("[destroy]", obj->attributes);
139b56b3d07SJens Wiklander 	if (obj->uuid)
140b56b3d07SJens Wiklander 		MSG_RAW("[destroy] obj uuid %pUl", (void *)obj->uuid);
141b56b3d07SJens Wiklander #endif
142b56b3d07SJens Wiklander 
143b56b3d07SJens Wiklander 	LIST_REMOVE(obj, link);
144b56b3d07SJens Wiklander 
145b56b3d07SJens Wiklander 	if (session_only) {
146b56b3d07SJens Wiklander 		/* Destroy object due to session closure */
147bc555ee0SVesa Jääskeläinen 		handle_put(get_object_handle_db(session),
148b56b3d07SJens Wiklander 			   pkcs11_object2handle(obj, session));
149b56b3d07SJens Wiklander 		cleanup_volatile_obj_ref(obj);
150b56b3d07SJens Wiklander 
151b56b3d07SJens Wiklander 		return;
152b56b3d07SJens Wiklander 	}
153b56b3d07SJens Wiklander 
154b56b3d07SJens Wiklander 	/* Destroy target object (persistent or not) */
155b56b3d07SJens Wiklander 	if (get_bool(obj->attributes, PKCS11_CKA_TOKEN)) {
156334316feSJens Wiklander 		assert(obj->uuid);
157334316feSJens Wiklander 		/* Try twice otherwise panic! */
158334316feSJens Wiklander 		if (unregister_persistent_object(session->token, obj->uuid) &&
159334316feSJens Wiklander 		    unregister_persistent_object(session->token, obj->uuid))
160b56b3d07SJens Wiklander 			TEE_Panic(0);
161334316feSJens Wiklander 
162bc555ee0SVesa Jääskeläinen 		handle_put(get_object_handle_db(session),
163334316feSJens Wiklander 			   pkcs11_object2handle(obj, session));
164334316feSJens Wiklander 		cleanup_persistent_object(obj, session->token);
165b56b3d07SJens Wiklander 	} else {
166bc555ee0SVesa Jääskeläinen 		handle_put(get_object_handle_db(session),
167b56b3d07SJens Wiklander 			   pkcs11_object2handle(obj, session));
168b56b3d07SJens Wiklander 		cleanup_volatile_obj_ref(obj);
169b56b3d07SJens Wiklander 	}
170b56b3d07SJens Wiklander }
171b56b3d07SJens Wiklander 
172bc555ee0SVesa Jääskeläinen static struct pkcs11_object *create_obj_instance(struct obj_attrs *head,
173bc555ee0SVesa Jääskeläinen 						 struct ck_token *token)
174b56b3d07SJens Wiklander {
175b56b3d07SJens Wiklander 	struct pkcs11_object *obj = NULL;
176b56b3d07SJens Wiklander 
177b56b3d07SJens Wiklander 	obj = TEE_Malloc(sizeof(struct pkcs11_object), TEE_MALLOC_FILL_ZERO);
178b56b3d07SJens Wiklander 	if (!obj)
179b56b3d07SJens Wiklander 		return NULL;
180b56b3d07SJens Wiklander 
181b56b3d07SJens Wiklander 	obj->key_handle = TEE_HANDLE_NULL;
182b56b3d07SJens Wiklander 	obj->attribs_hdl = TEE_HANDLE_NULL;
183b56b3d07SJens Wiklander 	obj->attributes = head;
184bc555ee0SVesa Jääskeläinen 	obj->token = token;
185b56b3d07SJens Wiklander 
186b56b3d07SJens Wiklander 	return obj;
187b56b3d07SJens Wiklander }
188b56b3d07SJens Wiklander 
189334316feSJens Wiklander struct pkcs11_object *create_token_object(struct obj_attrs *head,
190bc555ee0SVesa Jääskeläinen 					  TEE_UUID *uuid,
191bc555ee0SVesa Jääskeläinen 					  struct ck_token *token)
192334316feSJens Wiklander {
193bc555ee0SVesa Jääskeläinen 	struct pkcs11_object *obj = create_obj_instance(head, token);
194334316feSJens Wiklander 
195334316feSJens Wiklander 	if (obj)
196334316feSJens Wiklander 		obj->uuid = uuid;
197334316feSJens Wiklander 
198334316feSJens Wiklander 	return obj;
199334316feSJens Wiklander }
200334316feSJens Wiklander 
201b56b3d07SJens Wiklander /*
202b56b3d07SJens Wiklander  * create_object - create an PKCS11 TA object from its attributes and value
203b56b3d07SJens Wiklander  *
204b56b3d07SJens Wiklander  * @sess - session requesting object creation
205b56b3d07SJens Wiklander  * @head - reference to serialized attributes
206b56b3d07SJens Wiklander  * @out_handle - generated handle for the created object
207b56b3d07SJens Wiklander  */
208b56b3d07SJens Wiklander enum pkcs11_rc create_object(void *sess, struct obj_attrs *head,
209b56b3d07SJens Wiklander 			     uint32_t *out_handle)
210b56b3d07SJens Wiklander {
211fde67b24SEtienne Carriere 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
212b56b3d07SJens Wiklander 	struct pkcs11_object *obj = NULL;
213b56b3d07SJens Wiklander 	struct pkcs11_session *session = (struct pkcs11_session *)sess;
214b56b3d07SJens Wiklander 	uint32_t obj_handle = 0;
215b56b3d07SJens Wiklander 
216b56b3d07SJens Wiklander #ifdef DEBUG
217b56b3d07SJens Wiklander 	trace_attributes("[create]", head);
218b56b3d07SJens Wiklander #endif
219b56b3d07SJens Wiklander 
220b56b3d07SJens Wiklander 	/*
221b56b3d07SJens Wiklander 	 * We do not check the key attributes. At this point, key attributes
222b56b3d07SJens Wiklander 	 * are expected consistent and reliable.
223b56b3d07SJens Wiklander 	 */
224b56b3d07SJens Wiklander 
225bc555ee0SVesa Jääskeläinen 	obj = create_obj_instance(head, NULL);
226b56b3d07SJens Wiklander 	if (!obj)
227b56b3d07SJens Wiklander 		return PKCS11_CKR_DEVICE_MEMORY;
228b56b3d07SJens Wiklander 
22902dbcc7eSEtienne Carriere 	LIST_INSERT_HEAD(&temporary_object_list, obj, link);
23002dbcc7eSEtienne Carriere 
231b56b3d07SJens Wiklander 	/* Create a handle for the object in the session database */
232bc555ee0SVesa Jääskeläinen 	obj_handle = handle_get(get_object_handle_db(session), obj);
233b56b3d07SJens Wiklander 	if (!obj_handle) {
234b56b3d07SJens Wiklander 		rc = PKCS11_CKR_DEVICE_MEMORY;
235b56b3d07SJens Wiklander 		goto err;
236b56b3d07SJens Wiklander 	}
237b56b3d07SJens Wiklander 
238b56b3d07SJens Wiklander 	if (get_bool(obj->attributes, PKCS11_CKA_TOKEN)) {
239334316feSJens Wiklander 		TEE_Result res = TEE_SUCCESS;
240334316feSJens Wiklander 
241334316feSJens Wiklander 		/*
242334316feSJens Wiklander 		 * Get an ID for the persistent object
243334316feSJens Wiklander 		 * Create the file
244334316feSJens Wiklander 		 * Register the object in the persistent database
245334316feSJens Wiklander 		 * (move the full sequence to persisent_db.c?)
246334316feSJens Wiklander 		 */
247334316feSJens Wiklander 		size_t size = sizeof(struct obj_attrs) +
248334316feSJens Wiklander 			      obj->attributes->attrs_size;
249334316feSJens Wiklander 		uint32_t tee_obj_flags = TEE_DATA_FLAG_ACCESS_READ |
250334316feSJens Wiklander 					 TEE_DATA_FLAG_ACCESS_WRITE |
251334316feSJens Wiklander 					 TEE_DATA_FLAG_ACCESS_WRITE_META;
252334316feSJens Wiklander 
253334316feSJens Wiklander 		rc = create_object_uuid(get_session_token(session), obj);
254334316feSJens Wiklander 		if (rc)
255334316feSJens Wiklander 			goto err;
256334316feSJens Wiklander 
257334316feSJens Wiklander 		res = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE,
258334316feSJens Wiklander 						 obj->uuid, sizeof(TEE_UUID),
259334316feSJens Wiklander 						 tee_obj_flags,
260334316feSJens Wiklander 						 TEE_HANDLE_NULL,
261334316feSJens Wiklander 						 obj->attributes, size,
262334316feSJens Wiklander 						 &obj->attribs_hdl);
263334316feSJens Wiklander 		if (res) {
264334316feSJens Wiklander 			rc = tee2pkcs_error(res);
265334316feSJens Wiklander 			goto err;
266334316feSJens Wiklander 		}
267334316feSJens Wiklander 
268334316feSJens Wiklander 		rc = register_persistent_object(get_session_token(session),
269334316feSJens Wiklander 						obj->uuid);
270334316feSJens Wiklander 		if (rc)
271334316feSJens Wiklander 			goto err;
272334316feSJens Wiklander 
2730fafe5c7SVesa Jääskeläinen 		TEE_CloseObject(obj->attribs_hdl);
2740fafe5c7SVesa Jääskeläinen 		obj->attribs_hdl = TEE_HANDLE_NULL;
2750fafe5c7SVesa Jääskeläinen 
27602dbcc7eSEtienne Carriere 		/* Move object from temporary list to target token list */
27702dbcc7eSEtienne Carriere 		LIST_REMOVE(obj, link);
278334316feSJens Wiklander 		LIST_INSERT_HEAD(&session->token->object_list, obj, link);
279b56b3d07SJens Wiklander 	} else {
28002dbcc7eSEtienne Carriere 		/* Move object from temporary list to target session list */
28102dbcc7eSEtienne Carriere 		LIST_REMOVE(obj, link);
282b56b3d07SJens Wiklander 		LIST_INSERT_HEAD(get_session_objects(session), obj, link);
28302dbcc7eSEtienne Carriere 		rc = PKCS11_CKR_OK;
284b56b3d07SJens Wiklander 	}
285b56b3d07SJens Wiklander 
286b56b3d07SJens Wiklander 	*out_handle = obj_handle;
287b56b3d07SJens Wiklander 
288b56b3d07SJens Wiklander 	return PKCS11_CKR_OK;
289b56b3d07SJens Wiklander err:
290b56b3d07SJens Wiklander 	/* make sure that supplied "head" isn't freed */
291b56b3d07SJens Wiklander 	obj->attributes = NULL;
292bc555ee0SVesa Jääskeläinen 	handle_put(get_object_handle_db(session), obj_handle);
293b56b3d07SJens Wiklander 	if (get_bool(head, PKCS11_CKA_TOKEN))
294b56b3d07SJens Wiklander 		cleanup_persistent_object(obj, session->token);
295b56b3d07SJens Wiklander 	else
296b56b3d07SJens Wiklander 		cleanup_volatile_obj_ref(obj);
297b56b3d07SJens Wiklander 
298b56b3d07SJens Wiklander 	return rc;
299b56b3d07SJens Wiklander }
300b56b3d07SJens Wiklander 
301b56b3d07SJens Wiklander enum pkcs11_rc entry_create_object(struct pkcs11_client *client,
302b56b3d07SJens Wiklander 				   uint32_t ptypes, TEE_Param *params)
303b56b3d07SJens Wiklander {
304b56b3d07SJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
305b56b3d07SJens Wiklander 						TEE_PARAM_TYPE_NONE,
306b56b3d07SJens Wiklander 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
307b56b3d07SJens Wiklander 						TEE_PARAM_TYPE_NONE);
308b56b3d07SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
309b56b3d07SJens Wiklander 	TEE_Param *ctrl = params;
310b56b3d07SJens Wiklander 	TEE_Param *out = params + 2;
311b56b3d07SJens Wiklander 	struct serialargs ctrlargs = { };
312b56b3d07SJens Wiklander 	struct pkcs11_session *session = NULL;
313b56b3d07SJens Wiklander 	struct obj_attrs *head = NULL;
314b56b3d07SJens Wiklander 	struct pkcs11_object_head *template = NULL;
315b56b3d07SJens Wiklander 	size_t template_size = 0;
316b56b3d07SJens Wiklander 	uint32_t obj_handle = 0;
317b56b3d07SJens Wiklander 
318b56b3d07SJens Wiklander 	/*
319b56b3d07SJens Wiklander 	 * Collect the arguments of the request
320b56b3d07SJens Wiklander 	 */
321b56b3d07SJens Wiklander 
322b56b3d07SJens Wiklander 	if (!client || ptypes != exp_pt ||
323b56b3d07SJens Wiklander 	    out->memref.size != sizeof(obj_handle))
324b56b3d07SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
325b56b3d07SJens Wiklander 
326b56b3d07SJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
327b56b3d07SJens Wiklander 
32859a5257eSEtienne Carriere 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
329b56b3d07SJens Wiklander 	if (rc)
330b56b3d07SJens Wiklander 		return rc;
331b56b3d07SJens Wiklander 
332b56b3d07SJens Wiklander 	rc = serialargs_alloc_get_attributes(&ctrlargs, &template);
333b56b3d07SJens Wiklander 	if (rc)
334b56b3d07SJens Wiklander 		return rc;
335b56b3d07SJens Wiklander 
336b56b3d07SJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs)) {
337b56b3d07SJens Wiklander 		rc = PKCS11_CKR_ARGUMENTS_BAD;
338b56b3d07SJens Wiklander 		goto out;
339b56b3d07SJens Wiklander 	}
340b56b3d07SJens Wiklander 
341b56b3d07SJens Wiklander 	template_size = sizeof(*template) + template->attrs_size;
342b56b3d07SJens Wiklander 
343b56b3d07SJens Wiklander 	/*
344b56b3d07SJens Wiklander 	 * Prepare a clean initial state for the requested object attributes.
345b56b3d07SJens Wiklander 	 * Free temporary template once done.
346b56b3d07SJens Wiklander 	 */
347b56b3d07SJens Wiklander 	rc = create_attributes_from_template(&head, template, template_size,
348b56b3d07SJens Wiklander 					     NULL, PKCS11_FUNCTION_IMPORT,
3494cfce748SRuchika Gupta 					     PKCS11_PROCESSING_IMPORT,
3504cfce748SRuchika Gupta 					     PKCS11_CKO_UNDEFINED_ID);
351b56b3d07SJens Wiklander 	TEE_Free(template);
352b56b3d07SJens Wiklander 	template = NULL;
353b56b3d07SJens Wiklander 	if (rc)
354b56b3d07SJens Wiklander 		goto out;
355b56b3d07SJens Wiklander 
356b56b3d07SJens Wiklander 	/*
357b56b3d07SJens Wiklander 	 * Check target object attributes match target processing
358b56b3d07SJens Wiklander 	 * Check target object attributes match token state
359b56b3d07SJens Wiklander 	 */
360b56b3d07SJens Wiklander 	rc = check_created_attrs_against_processing(PKCS11_PROCESSING_IMPORT,
361b56b3d07SJens Wiklander 						    head);
362b56b3d07SJens Wiklander 	if (rc)
363b56b3d07SJens Wiklander 		goto out;
364b56b3d07SJens Wiklander 
365b56b3d07SJens Wiklander 	rc = check_created_attrs_against_token(session, head);
366b56b3d07SJens Wiklander 	if (rc)
367b56b3d07SJens Wiklander 		goto out;
368b56b3d07SJens Wiklander 
369b68aca61SRuchika Gupta 	rc = check_access_attrs_against_token(session, head);
370b68aca61SRuchika Gupta 	if (rc)
371b68aca61SRuchika Gupta 		goto out;
372b68aca61SRuchika Gupta 
373b56b3d07SJens Wiklander 	/*
374b56b3d07SJens Wiklander 	 * At this stage the object is almost created: all its attributes are
375b56b3d07SJens Wiklander 	 * referenced in @head, including the key value and are assumed
376b56b3d07SJens Wiklander 	 * reliable. Now need to register it and get a handle for it.
377b56b3d07SJens Wiklander 	 */
378b56b3d07SJens Wiklander 	rc = create_object(session, head, &obj_handle);
379b56b3d07SJens Wiklander 	if (rc)
380b56b3d07SJens Wiklander 		goto out;
381b56b3d07SJens Wiklander 
382b56b3d07SJens Wiklander 	/*
383b56b3d07SJens Wiklander 	 * Now obj_handle (through the related struct pkcs11_object
384e3737878SRuchika Gupta 	 * instance) owns the serialized buffer that holds the object
385b56b3d07SJens Wiklander 	 * attributes. We clear reference in head to NULL as the serializer
386b56b3d07SJens Wiklander 	 * object is now referred from obj_handle. This allows smooth pass
387b56b3d07SJens Wiklander 	 * through free at function exit.
388b56b3d07SJens Wiklander 	 */
389b56b3d07SJens Wiklander 	head = NULL;
390b56b3d07SJens Wiklander 
391b56b3d07SJens Wiklander 	TEE_MemMove(out->memref.buffer, &obj_handle, sizeof(obj_handle));
392b56b3d07SJens Wiklander 	out->memref.size = sizeof(obj_handle);
393b56b3d07SJens Wiklander 
394b56b3d07SJens Wiklander 	DMSG("PKCS11 session %"PRIu32": import object %#"PRIx32,
395b56b3d07SJens Wiklander 	     session->handle, obj_handle);
396b56b3d07SJens Wiklander 
397b56b3d07SJens Wiklander out:
398b56b3d07SJens Wiklander 	TEE_Free(template);
399b56b3d07SJens Wiklander 	TEE_Free(head);
400b56b3d07SJens Wiklander 
401b56b3d07SJens Wiklander 	return rc;
402b56b3d07SJens Wiklander }
403b56b3d07SJens Wiklander 
404b56b3d07SJens Wiklander enum pkcs11_rc entry_destroy_object(struct pkcs11_client *client,
405b56b3d07SJens Wiklander 				    uint32_t ptypes, TEE_Param *params)
406b56b3d07SJens Wiklander {
407b56b3d07SJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
408b56b3d07SJens Wiklander 						TEE_PARAM_TYPE_NONE,
409b56b3d07SJens Wiklander 						TEE_PARAM_TYPE_NONE,
410b56b3d07SJens Wiklander 						TEE_PARAM_TYPE_NONE);
411b56b3d07SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
412b56b3d07SJens Wiklander 	TEE_Param *ctrl = params;
413b56b3d07SJens Wiklander 	struct serialargs ctrlargs = { };
414b56b3d07SJens Wiklander 	uint32_t object_handle = 0;
415b56b3d07SJens Wiklander 	struct pkcs11_session *session = NULL;
416b56b3d07SJens Wiklander 	struct pkcs11_object *object = NULL;
417b56b3d07SJens Wiklander 
418b56b3d07SJens Wiklander 	if (!client || ptypes != exp_pt)
419b56b3d07SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
420b56b3d07SJens Wiklander 
421b56b3d07SJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
422b56b3d07SJens Wiklander 
42359a5257eSEtienne Carriere 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
424b56b3d07SJens Wiklander 	if (rc)
425b56b3d07SJens Wiklander 		return rc;
426b56b3d07SJens Wiklander 
427b56b3d07SJens Wiklander 	rc = serialargs_get_u32(&ctrlargs, &object_handle);
428b56b3d07SJens Wiklander 	if (rc)
429b56b3d07SJens Wiklander 		return rc;
430b56b3d07SJens Wiklander 
431b56b3d07SJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs))
432b56b3d07SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
433b56b3d07SJens Wiklander 
434b56b3d07SJens Wiklander 	object = pkcs11_handle2object(object_handle, session);
435b56b3d07SJens Wiklander 	if (!object)
436b56b3d07SJens Wiklander 		return PKCS11_CKR_OBJECT_HANDLE_INVALID;
437b56b3d07SJens Wiklander 
438fab91492SRuchika Gupta 	/* Only session objects can be destroyed during a read-only session */
439fab91492SRuchika Gupta 	if (get_bool(object->attributes, PKCS11_CKA_TOKEN) &&
440fab91492SRuchika Gupta 	    !pkcs11_session_is_read_write(session)) {
441fab91492SRuchika Gupta 		DMSG("Can't destroy persistent object");
442fab91492SRuchika Gupta 		return PKCS11_CKR_SESSION_READ_ONLY;
443fab91492SRuchika Gupta 	}
444fab91492SRuchika Gupta 
445fab91492SRuchika Gupta 	/*
446fab91492SRuchika Gupta 	 * Only public objects can be destroyed unless normal user is logged in
447fab91492SRuchika Gupta 	 */
448fab91492SRuchika Gupta 	rc = check_access_attrs_against_token(session, object->attributes);
449fab91492SRuchika Gupta 	if (rc)
450fab91492SRuchika Gupta 		return PKCS11_CKR_USER_NOT_LOGGED_IN;
451fab91492SRuchika Gupta 
452fab91492SRuchika Gupta 	/* Objects with PKCS11_CKA_DESTROYABLE as false aren't destroyable */
453fab91492SRuchika Gupta 	if (!get_bool(object->attributes, PKCS11_CKA_DESTROYABLE))
454fab91492SRuchika Gupta 		return PKCS11_CKR_ACTION_PROHIBITED;
455fab91492SRuchika Gupta 
456b56b3d07SJens Wiklander 	destroy_object(session, object, false);
457b56b3d07SJens Wiklander 
458b56b3d07SJens Wiklander 	DMSG("PKCS11 session %"PRIu32": destroy object %#"PRIx32,
459b56b3d07SJens Wiklander 	     session->handle, object_handle);
460b56b3d07SJens Wiklander 
461b56b3d07SJens Wiklander 	return rc;
462b56b3d07SJens Wiklander }
463dc99b202SRuchika Gupta 
464dc99b202SRuchika Gupta static void release_find_obj_context(struct pkcs11_find_objects *find_ctx)
465dc99b202SRuchika Gupta {
466dc99b202SRuchika Gupta 	if (!find_ctx)
467dc99b202SRuchika Gupta 		return;
468dc99b202SRuchika Gupta 
469dc99b202SRuchika Gupta 	TEE_Free(find_ctx->attributes);
470dc99b202SRuchika Gupta 	TEE_Free(find_ctx->handles);
471dc99b202SRuchika Gupta 	TEE_Free(find_ctx);
472dc99b202SRuchika Gupta }
473dc99b202SRuchika Gupta 
474dc99b202SRuchika Gupta static enum pkcs11_rc find_ctx_add(struct pkcs11_find_objects *find_ctx,
475dc99b202SRuchika Gupta 				   uint32_t handle)
476dc99b202SRuchika Gupta {
477dc99b202SRuchika Gupta 	uint32_t *hdls = TEE_Realloc(find_ctx->handles,
478dc99b202SRuchika Gupta 				     (find_ctx->count + 1) * sizeof(*hdls));
479dc99b202SRuchika Gupta 
480dc99b202SRuchika Gupta 	if (!hdls)
481dc99b202SRuchika Gupta 		return PKCS11_CKR_DEVICE_MEMORY;
482dc99b202SRuchika Gupta 
483dc99b202SRuchika Gupta 	find_ctx->handles = hdls;
484dc99b202SRuchika Gupta 
485dc99b202SRuchika Gupta 	*(find_ctx->handles + find_ctx->count) = handle;
486dc99b202SRuchika Gupta 	find_ctx->count++;
487dc99b202SRuchika Gupta 
488dc99b202SRuchika Gupta 	return PKCS11_CKR_OK;
489dc99b202SRuchika Gupta }
490dc99b202SRuchika Gupta 
491dc99b202SRuchika Gupta enum pkcs11_rc entry_find_objects_init(struct pkcs11_client *client,
492dc99b202SRuchika Gupta 				       uint32_t ptypes, TEE_Param *params)
493dc99b202SRuchika Gupta {
494dc99b202SRuchika Gupta 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
495dc99b202SRuchika Gupta 						TEE_PARAM_TYPE_NONE,
496dc99b202SRuchika Gupta 						TEE_PARAM_TYPE_NONE,
497dc99b202SRuchika Gupta 						TEE_PARAM_TYPE_NONE);
498dc99b202SRuchika Gupta 	TEE_Param *ctrl = params;
499dc99b202SRuchika Gupta 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
500dc99b202SRuchika Gupta 	struct serialargs ctrlargs = { };
501dc99b202SRuchika Gupta 	struct pkcs11_session *session = NULL;
502bc555ee0SVesa Jääskeläinen 	struct pkcs11_session *sess = NULL;
503dc99b202SRuchika Gupta 	struct pkcs11_object_head *template = NULL;
504dc99b202SRuchika Gupta 	struct obj_attrs *req_attrs = NULL;
505dc99b202SRuchika Gupta 	struct pkcs11_object *obj = NULL;
506dc99b202SRuchika Gupta 	struct pkcs11_find_objects *find_ctx = NULL;
507bc555ee0SVesa Jääskeläinen 	struct handle_db *object_db = NULL;
508dc99b202SRuchika Gupta 
509dc99b202SRuchika Gupta 	if (!client || ptypes != exp_pt)
510dc99b202SRuchika Gupta 		return PKCS11_CKR_ARGUMENTS_BAD;
511dc99b202SRuchika Gupta 
512dc99b202SRuchika Gupta 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
513dc99b202SRuchika Gupta 
514dc99b202SRuchika Gupta 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
515dc99b202SRuchika Gupta 	if (rc)
516dc99b202SRuchika Gupta 		return rc;
517dc99b202SRuchika Gupta 
518dc99b202SRuchika Gupta 	rc = serialargs_alloc_get_attributes(&ctrlargs, &template);
519dc99b202SRuchika Gupta 	if (rc)
520dc99b202SRuchika Gupta 		return rc;
521dc99b202SRuchika Gupta 
522dc99b202SRuchika Gupta 	if (serialargs_remaining_bytes(&ctrlargs)) {
523dc99b202SRuchika Gupta 		rc = PKCS11_CKR_ARGUMENTS_BAD;
524dc99b202SRuchika Gupta 		goto out;
525dc99b202SRuchika Gupta 	}
526dc99b202SRuchika Gupta 
527dc99b202SRuchika Gupta 	/* Search objects only if no operation is on-going */
528dc99b202SRuchika Gupta 	if (session_is_active(session)) {
529dc99b202SRuchika Gupta 		rc = PKCS11_CKR_OPERATION_ACTIVE;
530dc99b202SRuchika Gupta 		goto out;
531dc99b202SRuchika Gupta 	}
532dc99b202SRuchika Gupta 
533dc99b202SRuchika Gupta 	if (session->find_ctx) {
534dc99b202SRuchika Gupta 		EMSG("Active object search already in progress");
535dc99b202SRuchika Gupta 		rc = PKCS11_CKR_FUNCTION_FAILED;
536dc99b202SRuchika Gupta 		goto out;
537dc99b202SRuchika Gupta 	}
538dc99b202SRuchika Gupta 
539dc99b202SRuchika Gupta 	rc = sanitize_client_object(&req_attrs, template,
540dc99b202SRuchika Gupta 				    sizeof(*template) + template->attrs_size,
541dc99b202SRuchika Gupta 				    PKCS11_UNDEFINED_ID, PKCS11_UNDEFINED_ID);
542dc99b202SRuchika Gupta 	if (rc)
543dc99b202SRuchika Gupta 		goto out;
544dc99b202SRuchika Gupta 
545dc99b202SRuchika Gupta 	/* Must zero init the structure */
546dc99b202SRuchika Gupta 	find_ctx = TEE_Malloc(sizeof(*find_ctx), TEE_MALLOC_FILL_ZERO);
547dc99b202SRuchika Gupta 	if (!find_ctx) {
548dc99b202SRuchika Gupta 		rc = PKCS11_CKR_DEVICE_MEMORY;
549dc99b202SRuchika Gupta 		goto out;
550dc99b202SRuchika Gupta 	}
551dc99b202SRuchika Gupta 
552dc99b202SRuchika Gupta 	TEE_Free(template);
553dc99b202SRuchika Gupta 	template = NULL;
554dc99b202SRuchika Gupta 
555dc99b202SRuchika Gupta 	switch (get_class(req_attrs)) {
556dc99b202SRuchika Gupta 	case PKCS11_CKO_UNDEFINED_ID:
557dc99b202SRuchika Gupta 	/* Unspecified class searches among data objects */
558dc99b202SRuchika Gupta 	case PKCS11_CKO_SECRET_KEY:
559dc99b202SRuchika Gupta 	case PKCS11_CKO_PUBLIC_KEY:
560dc99b202SRuchika Gupta 	case PKCS11_CKO_PRIVATE_KEY:
561dc99b202SRuchika Gupta 	case PKCS11_CKO_DATA:
5624137952dSVesa Jääskeläinen 	case PKCS11_CKO_CERTIFICATE:
563dc99b202SRuchika Gupta 		break;
564dc99b202SRuchika Gupta 	default:
565dc99b202SRuchika Gupta 		EMSG("Find object of class %s (%"PRIu32") is not supported",
566dc99b202SRuchika Gupta 		     id2str_class(get_class(req_attrs)),
567dc99b202SRuchika Gupta 		     get_class(req_attrs));
568dc99b202SRuchika Gupta 		rc = PKCS11_CKR_ARGUMENTS_BAD;
569dc99b202SRuchika Gupta 		goto out;
570dc99b202SRuchika Gupta 	}
571dc99b202SRuchika Gupta 
572dc99b202SRuchika Gupta 	/*
573dc99b202SRuchika Gupta 	 * Scan all objects (sessions and persistent ones) and set a list of
574dc99b202SRuchika Gupta 	 * candidates that match caller attributes.
575dc99b202SRuchika Gupta 	 */
576dc99b202SRuchika Gupta 
577bc555ee0SVesa Jääskeläinen 	/* Scan all session objects first */
578bc555ee0SVesa Jääskeläinen 	TAILQ_FOREACH(sess, get_session_list(session), link) {
579bc555ee0SVesa Jääskeläinen 		LIST_FOREACH(obj, &sess->object_list, link) {
580bc555ee0SVesa Jääskeläinen 			/*
581bc555ee0SVesa Jääskeläinen 			 * Skip all token objects as they could be from
582bc555ee0SVesa Jääskeläinen 			 * different token which the session does not have
583bc555ee0SVesa Jääskeläinen 			 * access
584bc555ee0SVesa Jääskeläinen 			 */
585bc555ee0SVesa Jääskeläinen 			if (obj->token)
586dc99b202SRuchika Gupta 				continue;
587dc99b202SRuchika Gupta 
588bc555ee0SVesa Jääskeläinen 			if (!attributes_match_reference(obj->attributes,
589bc555ee0SVesa Jääskeläinen 							req_attrs))
590dc99b202SRuchika Gupta 				continue;
591dc99b202SRuchika Gupta 
592bc555ee0SVesa Jääskeläinen 			rc = find_ctx_add(find_ctx,
593bc555ee0SVesa Jääskeläinen 					  pkcs11_object2handle(obj, session));
594dc99b202SRuchika Gupta 			if (rc)
595dc99b202SRuchika Gupta 				goto out;
596dc99b202SRuchika Gupta 		}
597bc555ee0SVesa Jääskeläinen 	}
598dc99b202SRuchika Gupta 
599bc555ee0SVesa Jääskeläinen 	object_db = get_object_handle_db(session);
600bc555ee0SVesa Jääskeläinen 
601bc555ee0SVesa Jääskeläinen 	/* Scan token objects */
602dc99b202SRuchika Gupta 	LIST_FOREACH(obj, &session->token->object_list, link) {
603dc99b202SRuchika Gupta 		uint32_t handle = 0;
604fa1ac767SRobin van der Gracht 		bool new_load = false;
605dc99b202SRuchika Gupta 
606fa1ac767SRobin van der Gracht 		if (!obj->attributes) {
607fa1ac767SRobin van der Gracht 			rc = load_persistent_object_attributes(obj);
608*b7964037SElvira Khabirova 			if (rc) {
609*b7964037SElvira Khabirova 				rc = PKCS11_CKR_GENERAL_ERROR;
610*b7964037SElvira Khabirova 				goto out;
611*b7964037SElvira Khabirova 			}
612dc99b202SRuchika Gupta 
613fa1ac767SRobin van der Gracht 			new_load = true;
614fa1ac767SRobin van der Gracht 		}
615fa1ac767SRobin van der Gracht 
616fa1ac767SRobin van der Gracht 		if (!obj->attributes ||
617fa1ac767SRobin van der Gracht 		    check_access_attrs_against_token(session,
618fa1ac767SRobin van der Gracht 						     obj->attributes) ||
619fa1ac767SRobin van der Gracht 		    !attributes_match_reference(obj->attributes, req_attrs)) {
620fa1ac767SRobin van der Gracht 			if (new_load)
621fa1ac767SRobin van der Gracht 				release_persistent_object_attributes(obj);
622fa1ac767SRobin van der Gracht 
623dc99b202SRuchika Gupta 			continue;
624dc99b202SRuchika Gupta 		}
625dc99b202SRuchika Gupta 
626bc555ee0SVesa Jääskeläinen 		/* Resolve object handle for object */
627dc99b202SRuchika Gupta 		handle = pkcs11_object2handle(obj, session);
628dc99b202SRuchika Gupta 		if (!handle) {
629bc555ee0SVesa Jääskeläinen 			handle = handle_get(object_db, obj);
630dc99b202SRuchika Gupta 			if (!handle) {
631dc99b202SRuchika Gupta 				rc = PKCS11_CKR_DEVICE_MEMORY;
632dc99b202SRuchika Gupta 				goto out;
633dc99b202SRuchika Gupta 			}
634dc99b202SRuchika Gupta 		}
635dc99b202SRuchika Gupta 
636dc99b202SRuchika Gupta 		rc = find_ctx_add(find_ctx, handle);
637dc99b202SRuchika Gupta 		if (rc)
638dc99b202SRuchika Gupta 			goto out;
639dc99b202SRuchika Gupta 	}
640dc99b202SRuchika Gupta 
641dc99b202SRuchika Gupta 	find_ctx->attributes = req_attrs;
642dc99b202SRuchika Gupta 	req_attrs = NULL;
643dc99b202SRuchika Gupta 	session->find_ctx = find_ctx;
644dc99b202SRuchika Gupta 	find_ctx = NULL;
645dc99b202SRuchika Gupta 	rc = PKCS11_CKR_OK;
646dc99b202SRuchika Gupta 
647dc99b202SRuchika Gupta out:
648dc99b202SRuchika Gupta 	TEE_Free(req_attrs);
649dc99b202SRuchika Gupta 	TEE_Free(template);
650dc99b202SRuchika Gupta 	release_find_obj_context(find_ctx);
651dc99b202SRuchika Gupta 
652dc99b202SRuchika Gupta 	return rc;
653dc99b202SRuchika Gupta }
654dc99b202SRuchika Gupta 
655dc99b202SRuchika Gupta enum pkcs11_rc entry_find_objects(struct pkcs11_client *client,
656dc99b202SRuchika Gupta 				  uint32_t ptypes, TEE_Param *params)
657dc99b202SRuchika Gupta {
658dc99b202SRuchika Gupta 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
659dc99b202SRuchika Gupta 						TEE_PARAM_TYPE_NONE,
660dc99b202SRuchika Gupta 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
661dc99b202SRuchika Gupta 						TEE_PARAM_TYPE_NONE);
662dc99b202SRuchika Gupta 	TEE_Param *ctrl = params;
663dc99b202SRuchika Gupta 	TEE_Param *out = params + 2;
664dc99b202SRuchika Gupta 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
665dc99b202SRuchika Gupta 	struct serialargs ctrlargs = { };
666dc99b202SRuchika Gupta 	struct pkcs11_session *session = NULL;
667dc99b202SRuchika Gupta 	struct pkcs11_find_objects *ctx = NULL;
668dc99b202SRuchika Gupta 	uint8_t *out_handles = NULL;
669dc99b202SRuchika Gupta 	size_t out_count = 0;
670dc99b202SRuchika Gupta 	size_t count = 0;
671dc99b202SRuchika Gupta 
672dc99b202SRuchika Gupta 	if (!client || ptypes != exp_pt)
673dc99b202SRuchika Gupta 		return PKCS11_CKR_ARGUMENTS_BAD;
674dc99b202SRuchika Gupta 
675dc99b202SRuchika Gupta 	out_count = out->memref.size / sizeof(uint32_t);
676dc99b202SRuchika Gupta 	out_handles = out->memref.buffer;
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 	ctx = session->find_ctx;
688dc99b202SRuchika Gupta 
689dc99b202SRuchika Gupta 	if (!ctx)
690dc99b202SRuchika Gupta 		return PKCS11_CKR_OPERATION_NOT_INITIALIZED;
691dc99b202SRuchika Gupta 
692dc99b202SRuchika Gupta 	for (count = 0; ctx->next < ctx->count && count < out_count;
693dc99b202SRuchika Gupta 	     ctx->next++, count++)
694dc99b202SRuchika Gupta 		TEE_MemMove(out_handles + count * sizeof(uint32_t),
695dc99b202SRuchika Gupta 			    ctx->handles + ctx->next, sizeof(uint32_t));
696dc99b202SRuchika Gupta 
697dc99b202SRuchika Gupta 	/* Update output buffer according the number of handles provided */
698dc99b202SRuchika Gupta 	out->memref.size = count * sizeof(uint32_t);
699dc99b202SRuchika Gupta 
700dc99b202SRuchika Gupta 	DMSG("PKCS11 session %"PRIu32": finding objects", session->handle);
701dc99b202SRuchika Gupta 
702dc99b202SRuchika Gupta 	return PKCS11_CKR_OK;
703dc99b202SRuchika Gupta }
704dc99b202SRuchika Gupta 
705dc99b202SRuchika Gupta void release_session_find_obj_context(struct pkcs11_session *session)
706dc99b202SRuchika Gupta {
707dc99b202SRuchika Gupta 	release_find_obj_context(session->find_ctx);
708dc99b202SRuchika Gupta 	session->find_ctx = NULL;
709dc99b202SRuchika Gupta }
710dc99b202SRuchika Gupta 
711e3737878SRuchika Gupta enum pkcs11_rc entry_find_objects_final(struct pkcs11_client *client,
712dc99b202SRuchika Gupta 					uint32_t ptypes, TEE_Param *params)
713dc99b202SRuchika Gupta {
714dc99b202SRuchika Gupta 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
715dc99b202SRuchika Gupta 						TEE_PARAM_TYPE_NONE,
716dc99b202SRuchika Gupta 						TEE_PARAM_TYPE_NONE,
717dc99b202SRuchika Gupta 						TEE_PARAM_TYPE_NONE);
718dc99b202SRuchika Gupta 	TEE_Param *ctrl = params;
719dc99b202SRuchika Gupta 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
720dc99b202SRuchika Gupta 	struct serialargs ctrlargs = { };
721dc99b202SRuchika Gupta 	struct pkcs11_session *session = NULL;
722dc99b202SRuchika Gupta 
723dc99b202SRuchika Gupta 	if (!client || ptypes != exp_pt)
724dc99b202SRuchika Gupta 		return PKCS11_CKR_ARGUMENTS_BAD;
725dc99b202SRuchika Gupta 
726dc99b202SRuchika Gupta 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
727dc99b202SRuchika Gupta 
728dc99b202SRuchika Gupta 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
729dc99b202SRuchika Gupta 	if (rc)
730dc99b202SRuchika Gupta 		return rc;
731dc99b202SRuchika Gupta 
732dc99b202SRuchika Gupta 	if (serialargs_remaining_bytes(&ctrlargs))
733dc99b202SRuchika Gupta 		return PKCS11_CKR_ARGUMENTS_BAD;
734dc99b202SRuchika Gupta 
735dc99b202SRuchika Gupta 	if (!session->find_ctx)
736dc99b202SRuchika Gupta 		return PKCS11_CKR_OPERATION_NOT_INITIALIZED;
737dc99b202SRuchika Gupta 
738dc99b202SRuchika Gupta 	release_session_find_obj_context(session);
739dc99b202SRuchika Gupta 
740dc99b202SRuchika Gupta 	return PKCS11_CKR_OK;
741dc99b202SRuchika Gupta }
742783c1515SRuchika Gupta 
743e3737878SRuchika Gupta enum pkcs11_rc entry_get_attribute_value(struct pkcs11_client *client,
744783c1515SRuchika Gupta 					 uint32_t ptypes, TEE_Param *params)
745783c1515SRuchika Gupta {
746783c1515SRuchika Gupta 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
747783c1515SRuchika Gupta 						TEE_PARAM_TYPE_NONE,
748783c1515SRuchika Gupta 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
749783c1515SRuchika Gupta 						TEE_PARAM_TYPE_NONE);
750783c1515SRuchika Gupta 	TEE_Param *ctrl = params;
751783c1515SRuchika Gupta 	TEE_Param *out = params + 2;
752783c1515SRuchika Gupta 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
753783c1515SRuchika Gupta 	struct serialargs ctrlargs = { };
754783c1515SRuchika Gupta 	struct pkcs11_session *session = NULL;
755783c1515SRuchika Gupta 	struct pkcs11_object_head *template = NULL;
756783c1515SRuchika Gupta 	struct pkcs11_object *obj = NULL;
757783c1515SRuchika Gupta 	uint32_t object_handle = 0;
758783c1515SRuchika Gupta 	char *cur = NULL;
759783c1515SRuchika Gupta 	size_t len = 0;
760783c1515SRuchika Gupta 	char *end = NULL;
761783c1515SRuchika Gupta 	bool attr_sensitive = 0;
762783c1515SRuchika Gupta 	bool attr_type_invalid = 0;
763783c1515SRuchika Gupta 	bool buffer_too_small = 0;
764783c1515SRuchika Gupta 
765783c1515SRuchika Gupta 	if (!client || ptypes != exp_pt)
766783c1515SRuchika Gupta 		return PKCS11_CKR_ARGUMENTS_BAD;
767783c1515SRuchika Gupta 
768783c1515SRuchika Gupta 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
769783c1515SRuchika Gupta 
770783c1515SRuchika Gupta 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
771783c1515SRuchika Gupta 	if (rc)
772783c1515SRuchika Gupta 		return rc;
773783c1515SRuchika Gupta 
774783c1515SRuchika Gupta 	rc = serialargs_get(&ctrlargs, &object_handle, sizeof(uint32_t));
775783c1515SRuchika Gupta 	if (rc)
776783c1515SRuchika Gupta 		return rc;
777783c1515SRuchika Gupta 
778783c1515SRuchika Gupta 	rc = serialargs_alloc_get_attributes(&ctrlargs, &template);
779783c1515SRuchika Gupta 	if (rc)
780783c1515SRuchika Gupta 		return rc;
781783c1515SRuchika Gupta 
782783c1515SRuchika Gupta 	if (serialargs_remaining_bytes(&ctrlargs)) {
783783c1515SRuchika Gupta 		rc = PKCS11_CKR_ARGUMENTS_BAD;
784783c1515SRuchika Gupta 		goto out;
785783c1515SRuchika Gupta 	}
786783c1515SRuchika Gupta 
787783c1515SRuchika Gupta 	obj = pkcs11_handle2object(object_handle, session);
788783c1515SRuchika Gupta 	if (!obj) {
789783c1515SRuchika Gupta 		rc = PKCS11_CKR_OBJECT_HANDLE_INVALID;
790783c1515SRuchika Gupta 		goto out;
791783c1515SRuchika Gupta 	}
792783c1515SRuchika Gupta 
793783c1515SRuchika Gupta 	rc = check_access_attrs_against_token(session, obj->attributes);
794783c1515SRuchika Gupta 	if (rc) {
795783c1515SRuchika Gupta 		rc = PKCS11_CKR_OBJECT_HANDLE_INVALID;
796783c1515SRuchika Gupta 		goto out;
797783c1515SRuchika Gupta 	}
798783c1515SRuchika Gupta 
799783c1515SRuchika Gupta 	/* Iterate over attributes and set their values */
800783c1515SRuchika Gupta 	/*
801783c1515SRuchika Gupta 	 * 1. If the specified attribute (i.e., the attribute specified by the
802783c1515SRuchika Gupta 	 * type field) for the object cannot be revealed because the object is
803783c1515SRuchika Gupta 	 * sensitive or unextractable, then the ulValueLen field in that triple
804783c1515SRuchika Gupta 	 * is modified to hold the value PKCS11_CK_UNAVAILABLE_INFORMATION.
805783c1515SRuchika Gupta 	 *
806783c1515SRuchika Gupta 	 * 2. Otherwise, if the specified value for the object is invalid (the
807783c1515SRuchika Gupta 	 * object does not possess such an attribute), then the ulValueLen field
808783c1515SRuchika Gupta 	 * in that triple is modified to hold the value
809783c1515SRuchika Gupta 	 * PKCS11_CK_UNAVAILABLE_INFORMATION.
810783c1515SRuchika Gupta 	 *
811783c1515SRuchika Gupta 	 * 3. Otherwise, if the pValue field has the value NULL_PTR, then the
812783c1515SRuchika Gupta 	 * ulValueLen field is modified to hold the exact length of the
813783c1515SRuchika Gupta 	 * specified attribute for the object.
814783c1515SRuchika Gupta 	 *
815783c1515SRuchika Gupta 	 * 4. Otherwise, if the length specified in ulValueLen is large enough
816783c1515SRuchika Gupta 	 * to hold the value of the specified attribute for the object, then
817783c1515SRuchika Gupta 	 * that attribute is copied into the buffer located at pValue, and the
818783c1515SRuchika Gupta 	 * ulValueLen field is modified to hold the exact length of the
819783c1515SRuchika Gupta 	 * attribute.
820783c1515SRuchika Gupta 	 *
821783c1515SRuchika Gupta 	 * 5. Otherwise, the ulValueLen field is modified to hold the value
822783c1515SRuchika Gupta 	 * PKCS11_CK_UNAVAILABLE_INFORMATION.
823783c1515SRuchika Gupta 	 */
824783c1515SRuchika Gupta 	cur = (char *)template + sizeof(struct pkcs11_object_head);
825783c1515SRuchika Gupta 	end = cur + template->attrs_size;
826783c1515SRuchika Gupta 
827783c1515SRuchika Gupta 	for (; cur < end; cur += len) {
828783c1515SRuchika Gupta 		struct pkcs11_attribute_head *cli_ref = (void *)cur;
82918cbc7a2SVesa Jääskeläinen 		struct pkcs11_attribute_head cli_head = { };
83018cbc7a2SVesa Jääskeläinen 		void *data_ptr = NULL;
831783c1515SRuchika Gupta 
83218cbc7a2SVesa Jääskeläinen 		/* Make copy of header so that is aligned properly. */
83318cbc7a2SVesa Jääskeläinen 		TEE_MemMove(&cli_head, cli_ref, sizeof(cli_head));
83418cbc7a2SVesa Jääskeläinen 
83518cbc7a2SVesa Jääskeläinen 		len = sizeof(*cli_ref) + cli_head.size;
836783c1515SRuchika Gupta 
837372064dcSRuchika Gupta 		/* We don't support getting value of indirect templates */
838372064dcSRuchika Gupta 		if (pkcs11_attr_has_indirect_attributes(cli_head.id)) {
839372064dcSRuchika Gupta 			attr_type_invalid = 1;
840372064dcSRuchika Gupta 			continue;
841372064dcSRuchika Gupta 		}
842372064dcSRuchika Gupta 
843783c1515SRuchika Gupta 		/* Check 1. */
84418cbc7a2SVesa Jääskeläinen 		if (!attribute_is_exportable(&cli_head, obj)) {
84518cbc7a2SVesa Jääskeläinen 			cli_head.size = PKCS11_CK_UNAVAILABLE_INFORMATION;
84618cbc7a2SVesa Jääskeläinen 			TEE_MemMove(&cli_ref->size, &cli_head.size,
84718cbc7a2SVesa Jääskeläinen 				    sizeof(cli_head.size));
848783c1515SRuchika Gupta 			attr_sensitive = 1;
849783c1515SRuchika Gupta 			continue;
850783c1515SRuchika Gupta 		}
851783c1515SRuchika Gupta 
85218cbc7a2SVesa Jääskeläinen 		/* Get real data pointer from template data */
853f3178382SVesa Jääskeläinen 		data_ptr = cli_head.size ? cli_ref->data : NULL;
85418cbc7a2SVesa Jääskeläinen 
855783c1515SRuchika Gupta 		/*
856783c1515SRuchika Gupta 		 * We assume that if size is 0, pValue was NULL, so we return
857783c1515SRuchika Gupta 		 * the size of the required buffer for it (3., 4.)
858783c1515SRuchika Gupta 		 */
859f3178382SVesa Jääskeläinen 		rc = get_attribute(obj->attributes, cli_head.id, data_ptr,
86018cbc7a2SVesa Jääskeläinen 				   &cli_head.size);
861783c1515SRuchika Gupta 		/* Check 2. */
862783c1515SRuchika Gupta 		switch (rc) {
863783c1515SRuchika Gupta 		case PKCS11_CKR_OK:
864783c1515SRuchika Gupta 			break;
865783c1515SRuchika Gupta 		case PKCS11_RV_NOT_FOUND:
86618cbc7a2SVesa Jääskeläinen 			cli_head.size = PKCS11_CK_UNAVAILABLE_INFORMATION;
867783c1515SRuchika Gupta 			attr_type_invalid = 1;
868783c1515SRuchika Gupta 			break;
869783c1515SRuchika Gupta 		case PKCS11_CKR_BUFFER_TOO_SMALL:
870f3178382SVesa Jääskeläinen 			if (data_ptr)
871783c1515SRuchika Gupta 				buffer_too_small = 1;
872783c1515SRuchika Gupta 			break;
873783c1515SRuchika Gupta 		default:
874783c1515SRuchika Gupta 			rc = PKCS11_CKR_GENERAL_ERROR;
875783c1515SRuchika Gupta 			goto out;
876783c1515SRuchika Gupta 		}
87718cbc7a2SVesa Jääskeläinen 
87818cbc7a2SVesa Jääskeläinen 		TEE_MemMove(&cli_ref->size, &cli_head.size,
87918cbc7a2SVesa Jääskeläinen 			    sizeof(cli_head.size));
880783c1515SRuchika Gupta 	}
881783c1515SRuchika Gupta 
882783c1515SRuchika Gupta 	/*
883783c1515SRuchika Gupta 	 * If case 1 applies to any of the requested attributes, then the call
884783c1515SRuchika Gupta 	 * should return the value CKR_ATTRIBUTE_SENSITIVE. If case 2 applies to
885783c1515SRuchika Gupta 	 * any of the requested attributes, then the call should return the
886783c1515SRuchika Gupta 	 * value CKR_ATTRIBUTE_TYPE_INVALID. If case 5 applies to any of the
887783c1515SRuchika Gupta 	 * requested attributes, then the call should return the value
888783c1515SRuchika Gupta 	 * CKR_BUFFER_TOO_SMALL. As usual, if more than one of these error codes
889783c1515SRuchika Gupta 	 * is applicable, Cryptoki may return any of them. Only if none of them
890783c1515SRuchika Gupta 	 * applies to any of the requested attributes will CKR_OK be returned.
891783c1515SRuchika Gupta 	 */
892783c1515SRuchika Gupta 
893783c1515SRuchika Gupta 	rc = PKCS11_CKR_OK;
894783c1515SRuchika Gupta 	if (attr_sensitive)
895783c1515SRuchika Gupta 		rc = PKCS11_CKR_ATTRIBUTE_SENSITIVE;
896783c1515SRuchika Gupta 	if (attr_type_invalid)
897783c1515SRuchika Gupta 		rc = PKCS11_CKR_ATTRIBUTE_TYPE_INVALID;
898783c1515SRuchika Gupta 	if (buffer_too_small)
899783c1515SRuchika Gupta 		rc = PKCS11_CKR_BUFFER_TOO_SMALL;
900783c1515SRuchika Gupta 
901783c1515SRuchika Gupta 	/* Move updated template to out buffer */
902783c1515SRuchika Gupta 	TEE_MemMove(out->memref.buffer, template, out->memref.size);
903783c1515SRuchika Gupta 
904783c1515SRuchika Gupta 	DMSG("PKCS11 session %"PRIu32": get attributes %#"PRIx32,
905783c1515SRuchika Gupta 	     session->handle, object_handle);
906783c1515SRuchika Gupta 
907783c1515SRuchika Gupta out:
908783c1515SRuchika Gupta 	TEE_Free(template);
909783c1515SRuchika Gupta 
910783c1515SRuchika Gupta 	return rc;
911783c1515SRuchika Gupta }
912783c1515SRuchika Gupta 
913e3737878SRuchika Gupta enum pkcs11_rc entry_get_object_size(struct pkcs11_client *client,
914783c1515SRuchika Gupta 				     uint32_t ptypes, TEE_Param *params)
915783c1515SRuchika Gupta {
916783c1515SRuchika Gupta 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
917783c1515SRuchika Gupta 						TEE_PARAM_TYPE_NONE,
918783c1515SRuchika Gupta 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
919783c1515SRuchika Gupta 						TEE_PARAM_TYPE_NONE);
920783c1515SRuchika Gupta 	TEE_Param *ctrl = params;
921783c1515SRuchika Gupta 	TEE_Param *out = params + 2;
922783c1515SRuchika Gupta 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
923783c1515SRuchika Gupta 	struct serialargs ctrlargs = { };
924783c1515SRuchika Gupta 	struct pkcs11_session *session = NULL;
925783c1515SRuchika Gupta 	uint32_t object_handle = 0;
926783c1515SRuchika Gupta 	struct pkcs11_object *obj = NULL;
927783c1515SRuchika Gupta 	uint32_t obj_size = 0;
928783c1515SRuchika Gupta 
929783c1515SRuchika Gupta 	if (!client || ptypes != exp_pt)
930783c1515SRuchika Gupta 		return PKCS11_CKR_ARGUMENTS_BAD;
931783c1515SRuchika Gupta 
932783c1515SRuchika Gupta 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
933783c1515SRuchika Gupta 
934783c1515SRuchika Gupta 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
935783c1515SRuchika Gupta 	if (rc)
936783c1515SRuchika Gupta 		return rc;
937783c1515SRuchika Gupta 
938783c1515SRuchika Gupta 	rc = serialargs_get(&ctrlargs, &object_handle, sizeof(uint32_t));
939783c1515SRuchika Gupta 	if (rc)
940783c1515SRuchika Gupta 		return rc;
941783c1515SRuchika Gupta 
942783c1515SRuchika Gupta 	if (serialargs_remaining_bytes(&ctrlargs))
943783c1515SRuchika Gupta 		return PKCS11_CKR_ARGUMENTS_BAD;
944783c1515SRuchika Gupta 
945783c1515SRuchika Gupta 	obj = pkcs11_handle2object(object_handle, session);
946783c1515SRuchika Gupta 	if (!obj)
947783c1515SRuchika Gupta 		return PKCS11_CKR_OBJECT_HANDLE_INVALID;
948783c1515SRuchika Gupta 
949783c1515SRuchika Gupta 	rc = check_access_attrs_against_token(session, obj->attributes);
950783c1515SRuchika Gupta 	if (rc)
951783c1515SRuchika Gupta 		return PKCS11_CKR_OBJECT_HANDLE_INVALID;
952783c1515SRuchika Gupta 
953783c1515SRuchika Gupta 	if (out->memref.size != sizeof(uint32_t))
954783c1515SRuchika Gupta 		return PKCS11_CKR_ARGUMENTS_BAD;
955783c1515SRuchika Gupta 
956783c1515SRuchika Gupta 	obj_size = ((struct obj_attrs *)obj->attributes)->attrs_size +
957783c1515SRuchika Gupta 		   sizeof(struct obj_attrs);
958783c1515SRuchika Gupta 	TEE_MemMove(out->memref.buffer, &obj_size, sizeof(obj_size));
959783c1515SRuchika Gupta 
960783c1515SRuchika Gupta 	return PKCS11_CKR_OK;
961783c1515SRuchika Gupta }
9622d25a9bcSRuchika Gupta 
9632d25a9bcSRuchika Gupta enum pkcs11_rc entry_set_attribute_value(struct pkcs11_client *client,
9642d25a9bcSRuchika Gupta 					 uint32_t ptypes, TEE_Param *params)
9652d25a9bcSRuchika Gupta {
9662d25a9bcSRuchika Gupta 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
9672d25a9bcSRuchika Gupta 						TEE_PARAM_TYPE_NONE,
9682d25a9bcSRuchika Gupta 						TEE_PARAM_TYPE_NONE,
9692d25a9bcSRuchika Gupta 						TEE_PARAM_TYPE_NONE);
9702d25a9bcSRuchika Gupta 	TEE_Param *ctrl = params;
9712d25a9bcSRuchika Gupta 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
9722d25a9bcSRuchika Gupta 	struct serialargs ctrlargs = { };
9732d25a9bcSRuchika Gupta 	struct pkcs11_session *session = NULL;
9742d25a9bcSRuchika Gupta 	struct pkcs11_object_head *template = NULL;
9752d25a9bcSRuchika Gupta 	size_t template_size = 0;
9762d25a9bcSRuchika Gupta 	struct pkcs11_object *obj = NULL;
9772d25a9bcSRuchika Gupta 	struct obj_attrs *head = NULL;
9782d25a9bcSRuchika Gupta 	uint32_t object_handle = 0;
9792d25a9bcSRuchika Gupta 	enum processing_func function = PKCS11_FUNCTION_MODIFY;
9802d25a9bcSRuchika Gupta 
9812d25a9bcSRuchika Gupta 	if (!client || ptypes != exp_pt)
9822d25a9bcSRuchika Gupta 		return PKCS11_CKR_ARGUMENTS_BAD;
9832d25a9bcSRuchika Gupta 
9842d25a9bcSRuchika Gupta 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
9852d25a9bcSRuchika Gupta 
9862d25a9bcSRuchika Gupta 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
9872d25a9bcSRuchika Gupta 	if (rc)
9882d25a9bcSRuchika Gupta 		return rc;
9892d25a9bcSRuchika Gupta 
9902d25a9bcSRuchika Gupta 	rc = serialargs_get(&ctrlargs, &object_handle, sizeof(uint32_t));
9912d25a9bcSRuchika Gupta 	if (rc)
9922d25a9bcSRuchika Gupta 		return rc;
9932d25a9bcSRuchika Gupta 
9942d25a9bcSRuchika Gupta 	rc = serialargs_alloc_get_attributes(&ctrlargs, &template);
9952d25a9bcSRuchika Gupta 	if (rc)
9962d25a9bcSRuchika Gupta 		return rc;
9972d25a9bcSRuchika Gupta 
9982d25a9bcSRuchika Gupta 	if (serialargs_remaining_bytes(&ctrlargs)) {
9992d25a9bcSRuchika Gupta 		rc = PKCS11_CKR_ARGUMENTS_BAD;
10002d25a9bcSRuchika Gupta 		goto out;
10012d25a9bcSRuchika Gupta 	}
10022d25a9bcSRuchika Gupta 
10032d25a9bcSRuchika Gupta 	obj = pkcs11_handle2object(object_handle, session);
10042d25a9bcSRuchika Gupta 	if (!obj) {
10052d25a9bcSRuchika Gupta 		rc = PKCS11_CKR_OBJECT_HANDLE_INVALID;
10062d25a9bcSRuchika Gupta 		goto out;
10072d25a9bcSRuchika Gupta 	}
10082d25a9bcSRuchika Gupta 
10092d25a9bcSRuchika Gupta 	/* Only session objects can be modified during a read-only session */
10102d25a9bcSRuchika Gupta 	if (object_is_token(obj->attributes) &&
10112d25a9bcSRuchika Gupta 	    !pkcs11_session_is_read_write(session)) {
10122d25a9bcSRuchika Gupta 		DMSG("Can't modify persistent object in a RO session");
10132d25a9bcSRuchika Gupta 		rc = PKCS11_CKR_SESSION_READ_ONLY;
10142d25a9bcSRuchika Gupta 		goto out;
10152d25a9bcSRuchika Gupta 	}
10162d25a9bcSRuchika Gupta 
10172d25a9bcSRuchika Gupta 	/*
10182d25a9bcSRuchika Gupta 	 * Only public objects can be modified unless normal user is logged in
10192d25a9bcSRuchika Gupta 	 */
10202d25a9bcSRuchika Gupta 	rc = check_access_attrs_against_token(session, obj->attributes);
10212d25a9bcSRuchika Gupta 	if (rc) {
10222d25a9bcSRuchika Gupta 		rc = PKCS11_CKR_USER_NOT_LOGGED_IN;
10232d25a9bcSRuchika Gupta 		goto out;
10242d25a9bcSRuchika Gupta 	}
10252d25a9bcSRuchika Gupta 
10262d25a9bcSRuchika Gupta 	/* Objects with PKCS11_CKA_MODIFIABLE as false aren't modifiable */
10272d25a9bcSRuchika Gupta 	if (!object_is_modifiable(obj->attributes)) {
10282d25a9bcSRuchika Gupta 		rc = PKCS11_CKR_ACTION_PROHIBITED;
10292d25a9bcSRuchika Gupta 		goto out;
10302d25a9bcSRuchika Gupta 	}
10312d25a9bcSRuchika Gupta 
10322d25a9bcSRuchika Gupta 	template_size = sizeof(*template) + template->attrs_size;
10332d25a9bcSRuchika Gupta 
10342d25a9bcSRuchika Gupta 	/*
10352d25a9bcSRuchika Gupta 	 * Prepare a clean initial state (@head) for the template. Helps in
10362d25a9bcSRuchika Gupta 	 * removing any duplicates or inconsistent values from the
10372d25a9bcSRuchika Gupta 	 * template.
10382d25a9bcSRuchika Gupta 	 */
10392d25a9bcSRuchika Gupta 	rc = create_attributes_from_template(&head, template, template_size,
10402d25a9bcSRuchika Gupta 					     NULL, function,
10412d25a9bcSRuchika Gupta 					     PKCS11_CKM_UNDEFINED_ID,
10422d25a9bcSRuchika Gupta 					     PKCS11_CKO_UNDEFINED_ID);
10432d25a9bcSRuchika Gupta 	if (rc)
10442d25a9bcSRuchika Gupta 		goto out;
10452d25a9bcSRuchika Gupta 
10462d25a9bcSRuchika Gupta 	/* Check the attributes in @head to see if they are modifiable */
10472d25a9bcSRuchika Gupta 	rc = check_attrs_against_modification(session, head, obj, function);
10482d25a9bcSRuchika Gupta 	if (rc)
10492d25a9bcSRuchika Gupta 		goto out;
10502d25a9bcSRuchika Gupta 
10512d25a9bcSRuchika Gupta 	/*
10522d25a9bcSRuchika Gupta 	 * All checks complete. The attributes in @head have been checked and
10532d25a9bcSRuchika Gupta 	 * can now be used to set/modify the object attributes.
10542d25a9bcSRuchika Gupta 	 */
10552d25a9bcSRuchika Gupta 	rc = modify_attributes_list(&obj->attributes, head);
10562d25a9bcSRuchika Gupta 	if (rc)
10572d25a9bcSRuchika Gupta 		goto out;
10582d25a9bcSRuchika Gupta 
1059402d884aSRuchika Gupta 	if (get_bool(obj->attributes, PKCS11_CKA_TOKEN)) {
1060402d884aSRuchika Gupta 		rc = update_persistent_object_attributes(obj);
1061402d884aSRuchika Gupta 		if (rc)
1062402d884aSRuchika Gupta 			goto out;
1063402d884aSRuchika Gupta 	}
1064402d884aSRuchika Gupta 
10652d25a9bcSRuchika Gupta 	DMSG("PKCS11 session %"PRIu32": set attributes %#"PRIx32,
10662d25a9bcSRuchika Gupta 	     session->handle, object_handle);
10672d25a9bcSRuchika Gupta 
10682d25a9bcSRuchika Gupta out:
10692d25a9bcSRuchika Gupta 	TEE_Free(head);
10702d25a9bcSRuchika Gupta 	TEE_Free(template);
10712d25a9bcSRuchika Gupta 	return rc;
10722d25a9bcSRuchika Gupta }
1073bc09507cSRuchika Gupta 
1074bc09507cSRuchika Gupta enum pkcs11_rc entry_copy_object(struct pkcs11_client *client, uint32_t ptypes,
1075bc09507cSRuchika Gupta 				 TEE_Param *params)
1076bc09507cSRuchika Gupta {
1077bc09507cSRuchika Gupta 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
1078bc09507cSRuchika Gupta 						TEE_PARAM_TYPE_NONE,
1079bc09507cSRuchika Gupta 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
1080bc09507cSRuchika Gupta 						TEE_PARAM_TYPE_NONE);
1081bc09507cSRuchika Gupta 	TEE_Param *ctrl = params;
1082bc09507cSRuchika Gupta 	TEE_Param *out = params + 2;
1083bc09507cSRuchika Gupta 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
1084bc09507cSRuchika Gupta 	struct serialargs ctrlargs = { };
1085bc09507cSRuchika Gupta 	struct pkcs11_session *session = NULL;
1086bc09507cSRuchika Gupta 	struct pkcs11_object_head *template = NULL;
1087bc09507cSRuchika Gupta 	struct obj_attrs *head = NULL;
1088bc09507cSRuchika Gupta 	struct obj_attrs *head_new = NULL;
1089bc09507cSRuchika Gupta 	size_t template_size = 0;
1090bc09507cSRuchika Gupta 	struct pkcs11_object *obj = NULL;
1091bc09507cSRuchika Gupta 	uint32_t object_handle = 0;
1092bc09507cSRuchika Gupta 	uint32_t obj_handle = 0;
1093bc09507cSRuchika Gupta 	enum processing_func function = PKCS11_FUNCTION_COPY;
1094bc09507cSRuchika Gupta 	enum pkcs11_class_id class = PKCS11_CKO_UNDEFINED_ID;
1095bc09507cSRuchika Gupta 
1096bc09507cSRuchika Gupta 	if (!client || ptypes != exp_pt ||
1097bc09507cSRuchika Gupta 	    out->memref.size != sizeof(obj_handle))
1098bc09507cSRuchika Gupta 		return PKCS11_CKR_ARGUMENTS_BAD;
1099bc09507cSRuchika Gupta 
1100bc09507cSRuchika Gupta 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
1101bc09507cSRuchika Gupta 
1102bc09507cSRuchika Gupta 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
1103bc09507cSRuchika Gupta 	if (rc)
1104bc09507cSRuchika Gupta 		return rc;
1105bc09507cSRuchika Gupta 
1106bc09507cSRuchika Gupta 	rc = serialargs_get(&ctrlargs, &object_handle, sizeof(uint32_t));
1107bc09507cSRuchika Gupta 	if (rc)
1108bc09507cSRuchika Gupta 		return rc;
1109bc09507cSRuchika Gupta 
1110bc09507cSRuchika Gupta 	rc = serialargs_alloc_get_attributes(&ctrlargs, &template);
1111bc09507cSRuchika Gupta 	if (rc)
1112bc09507cSRuchika Gupta 		return rc;
1113bc09507cSRuchika Gupta 
1114bc09507cSRuchika Gupta 	if (serialargs_remaining_bytes(&ctrlargs)) {
1115bc09507cSRuchika Gupta 		rc = PKCS11_CKR_ARGUMENTS_BAD;
1116bc09507cSRuchika Gupta 		goto out;
1117bc09507cSRuchika Gupta 	}
1118bc09507cSRuchika Gupta 
1119bc09507cSRuchika Gupta 	obj = pkcs11_handle2object(object_handle, session);
1120bc09507cSRuchika Gupta 	if (!obj) {
1121bc09507cSRuchika Gupta 		rc = PKCS11_CKR_OBJECT_HANDLE_INVALID;
1122bc09507cSRuchika Gupta 		goto out;
1123bc09507cSRuchika Gupta 	}
1124bc09507cSRuchika Gupta 
1125bc09507cSRuchika Gupta 	/* Only session objects can be modified during a read-only session */
1126bc09507cSRuchika Gupta 	if (object_is_token(obj->attributes) &&
1127bc09507cSRuchika Gupta 	    !pkcs11_session_is_read_write(session)) {
1128bc09507cSRuchika Gupta 		DMSG("Can't modify persistent object in a RO session");
1129bc09507cSRuchika Gupta 		rc = PKCS11_CKR_SESSION_READ_ONLY;
1130bc09507cSRuchika Gupta 		goto out;
1131bc09507cSRuchika Gupta 	}
1132bc09507cSRuchika Gupta 
1133bc09507cSRuchika Gupta 	/*
1134bc09507cSRuchika Gupta 	 * Only public objects can be modified unless normal user is logged in
1135bc09507cSRuchika Gupta 	 */
1136bc09507cSRuchika Gupta 	rc = check_access_attrs_against_token(session, obj->attributes);
1137bc09507cSRuchika Gupta 	if (rc) {
1138bc09507cSRuchika Gupta 		rc = PKCS11_CKR_USER_NOT_LOGGED_IN;
1139bc09507cSRuchika Gupta 		goto out;
1140bc09507cSRuchika Gupta 	}
1141bc09507cSRuchika Gupta 
1142bc09507cSRuchika Gupta 	/* Objects with PKCS11_CKA_COPYABLE as false can't be copied */
1143bc09507cSRuchika Gupta 	if (!object_is_copyable(obj->attributes)) {
1144bc09507cSRuchika Gupta 		rc = PKCS11_CKR_ACTION_PROHIBITED;
1145bc09507cSRuchika Gupta 		goto out;
1146bc09507cSRuchika Gupta 	}
1147bc09507cSRuchika Gupta 
1148bc09507cSRuchika Gupta 	template_size = sizeof(*template) + template->attrs_size;
1149bc09507cSRuchika Gupta 
1150bc09507cSRuchika Gupta 	/*
1151bc09507cSRuchika Gupta 	 * Prepare a clean initial state (@head) for the template. Helps in
1152bc09507cSRuchika Gupta 	 * removing any duplicates or inconsistent values from the
1153bc09507cSRuchika Gupta 	 * template.
1154bc09507cSRuchika Gupta 	 */
1155bc09507cSRuchika Gupta 	rc = create_attributes_from_template(&head, template, template_size,
1156bc09507cSRuchika Gupta 					     NULL, function,
1157bc09507cSRuchika Gupta 					     PKCS11_CKM_UNDEFINED_ID,
1158bc09507cSRuchika Gupta 					     PKCS11_CKO_UNDEFINED_ID);
1159bc09507cSRuchika Gupta 	if (rc)
1160bc09507cSRuchika Gupta 		goto out;
1161bc09507cSRuchika Gupta 
1162bc09507cSRuchika Gupta 	/* Check the attributes in @head to see if they are modifiable */
1163bc09507cSRuchika Gupta 	rc = check_attrs_against_modification(session, head, obj, function);
1164bc09507cSRuchika Gupta 	if (rc)
1165bc09507cSRuchika Gupta 		goto out;
1166bc09507cSRuchika Gupta 
1167bc09507cSRuchika Gupta 	class = get_class(obj->attributes);
1168bc09507cSRuchika Gupta 
1169bc09507cSRuchika Gupta 	if (class == PKCS11_CKO_SECRET_KEY ||
1170bc09507cSRuchika Gupta 	    class == PKCS11_CKO_PRIVATE_KEY) {
1171bc09507cSRuchika Gupta 		/*
1172bc09507cSRuchika Gupta 		 * If CKA_EXTRACTABLE attribute in passed template (@head) is
1173bc09507cSRuchika Gupta 		 * modified to CKA_FALSE, CKA_NEVER_EXTRACTABLE should also
1174bc09507cSRuchika Gupta 		 * change to CKA_FALSE in copied obj. So, add it to the
1175bc09507cSRuchika Gupta 		 * passed template.
1176bc09507cSRuchika Gupta 		 */
1177bc09507cSRuchika Gupta 		uint8_t bbool = 0;
1178bc09507cSRuchika Gupta 		uint32_t size = sizeof(bbool);
1179bc09507cSRuchika Gupta 
1180bc09507cSRuchika Gupta 		rc = get_attribute(head, PKCS11_CKA_EXTRACTABLE, &bbool, &size);
1181bc09507cSRuchika Gupta 		if (!rc && !bbool) {
1182bc09507cSRuchika Gupta 			rc = add_attribute(&head, PKCS11_CKA_NEVER_EXTRACTABLE,
1183bc09507cSRuchika Gupta 					   &bbool, sizeof(uint8_t));
1184bc09507cSRuchika Gupta 			if (rc)
1185bc09507cSRuchika Gupta 				goto out;
1186bc09507cSRuchika Gupta 		}
1187bc09507cSRuchika Gupta 		rc = PKCS11_CKR_OK;
1188bc09507cSRuchika Gupta 	}
1189bc09507cSRuchika Gupta 
1190bc09507cSRuchika Gupta 	/*
1191bc09507cSRuchika Gupta 	 * All checks have passed. Create a copy of the serialized buffer which
1192bc09507cSRuchika Gupta 	 * holds the object attributes in @head_new for the new object
1193bc09507cSRuchika Gupta 	 */
1194bc09507cSRuchika Gupta 	template_size = sizeof(*obj->attributes) + obj->attributes->attrs_size;
1195bc09507cSRuchika Gupta 	head_new = TEE_Malloc(template_size, TEE_MALLOC_FILL_ZERO);
1196bc09507cSRuchika Gupta 	if (!head_new) {
1197bc09507cSRuchika Gupta 		rc = PKCS11_CKR_DEVICE_MEMORY;
1198bc09507cSRuchika Gupta 		goto out;
1199bc09507cSRuchika Gupta 	}
1200bc09507cSRuchika Gupta 
1201bc09507cSRuchika Gupta 	TEE_MemMove(head_new, obj->attributes, template_size);
1202bc09507cSRuchika Gupta 
1203bc09507cSRuchika Gupta 	/*
1204bc09507cSRuchika Gupta 	 * Modify the copied attribute @head_new based on the template @head
1205bc09507cSRuchika Gupta 	 * given by the callee
1206bc09507cSRuchika Gupta 	 */
1207bc09507cSRuchika Gupta 	rc = modify_attributes_list(&head_new, head);
1208bc09507cSRuchika Gupta 	if (rc)
1209bc09507cSRuchika Gupta 		goto out;
1210bc09507cSRuchika Gupta 
1211bc09507cSRuchika Gupta 	/*
1212bc09507cSRuchika Gupta 	 * At this stage the object is almost created: all its attributes are
1213bc09507cSRuchika Gupta 	 * referenced in @head_new, including the key value and are assumed
1214bc09507cSRuchika Gupta 	 * reliable. Now need to register it and get a handle for it.
1215bc09507cSRuchika Gupta 	 */
1216bc09507cSRuchika Gupta 	rc = create_object(session, head_new, &obj_handle);
1217bc09507cSRuchika Gupta 	if (rc)
1218bc09507cSRuchika Gupta 		goto out;
1219bc09507cSRuchika Gupta 
1220bc09507cSRuchika Gupta 	/*
1221bc09507cSRuchika Gupta 	 * Now obj_handle (through the related struct pkcs11_object
1222e3737878SRuchika Gupta 	 * instance) owns the serialized buffer that holds the object
1223bc09507cSRuchika Gupta 	 * attributes. We clear reference in head to NULL as the serializer
1224bc09507cSRuchika Gupta 	 * object is now referred from obj_handle. This allows smooth pass
1225bc09507cSRuchika Gupta 	 * through free at function exit.
1226bc09507cSRuchika Gupta 	 */
1227bc09507cSRuchika Gupta 	head_new = NULL;
1228bc09507cSRuchika Gupta 
1229bc09507cSRuchika Gupta 	TEE_MemMove(out->memref.buffer, &obj_handle, sizeof(obj_handle));
1230bc09507cSRuchika Gupta 	out->memref.size = sizeof(obj_handle);
1231bc09507cSRuchika Gupta 
1232bc09507cSRuchika Gupta 	DMSG("PKCS11 session %"PRIu32": copy object %#"PRIx32,
1233bc09507cSRuchika Gupta 	     session->handle, obj_handle);
1234bc09507cSRuchika Gupta 
1235bc09507cSRuchika Gupta out:
1236bc09507cSRuchika Gupta 	TEE_Free(head_new);
1237bc09507cSRuchika Gupta 	TEE_Free(head);
1238bc09507cSRuchika Gupta 	TEE_Free(template);
1239bc09507cSRuchika Gupta 	return rc;
1240bc09507cSRuchika Gupta }
1241