xref: /optee_os/ta/pkcs11/src/object.c (revision bbfe5da7daee2ab8efcb94fe11938d444b940384)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2017-2020, Linaro Limited
4  */
5 
6 #include <assert.h>
7 #include <inttypes.h>
8 #include <string_ext.h>
9 #include <tee_internal_api.h>
10 #include <tee_internal_api_extensions.h>
11 
12 #include "attributes.h"
13 #include "handle.h"
14 #include "object.h"
15 #include "pkcs11_attributes.h"
16 #include "pkcs11_helpers.h"
17 #include "pkcs11_token.h"
18 #include "sanitize_object.h"
19 #include "serializer.h"
20 
21 static struct ck_token *get_session_token(void *session);
22 
23 struct pkcs11_object *pkcs11_handle2object(uint32_t handle,
24 					   struct pkcs11_session *session)
25 {
26 	struct pkcs11_object *object = NULL;
27 
28 	object = handle_lookup(get_object_handle_db(session), handle);
29 	if (!object)
30 		return NULL;
31 
32 	/*
33 	 * If object is session only then no extra checks are needed as session
34 	 * objects has flat access control space
35 	 */
36 	if (!object->token)
37 		return object;
38 
39 	/*
40 	 * Only allow access to token object if session is associated with
41 	 * the token
42 	 */
43 	if (object->token != get_session_token(session))
44 		return NULL;
45 
46 	return object;
47 }
48 
49 uint32_t pkcs11_object2handle(struct pkcs11_object *obj,
50 			      struct pkcs11_session *session)
51 {
52 	return handle_lookup_handle(get_object_handle_db(session), obj);
53 }
54 
55 /* Currently handle pkcs11 sessions and tokens */
56 
57 static struct object_list *get_session_objects(void *session)
58 {
59 	/* Currently supporting only pkcs11 session */
60 	struct pkcs11_session *ck_session = session;
61 
62 	return pkcs11_get_session_objects(ck_session);
63 }
64 
65 static struct ck_token *get_session_token(void *session)
66 {
67 	struct pkcs11_session *ck_session = session;
68 
69 	return pkcs11_session2token(ck_session);
70 }
71 
72 /* Release resources of a non-persistent object */
73 static void cleanup_volatile_obj_ref(struct pkcs11_object *obj)
74 {
75 	if (!obj)
76 		return;
77 
78 	if (obj->key_handle != TEE_HANDLE_NULL)
79 		TEE_FreeTransientObject(obj->key_handle);
80 
81 	if (obj->attribs_hdl != TEE_HANDLE_NULL)
82 		TEE_CloseObject(obj->attribs_hdl);
83 
84 	TEE_Free(obj->attributes);
85 	TEE_Free(obj->uuid);
86 	TEE_Free(obj);
87 }
88 
89 /* Release resources of a persistent object including volatile resources */
90 void cleanup_persistent_object(struct pkcs11_object *obj,
91 			       struct ck_token *token)
92 {
93 	TEE_Result res = TEE_SUCCESS;
94 
95 	if (!obj)
96 		return;
97 
98 	/* Open handle with write properties to destroy the object */
99 	if (obj->attribs_hdl != TEE_HANDLE_NULL)
100 		TEE_CloseObject(obj->attribs_hdl);
101 
102 	res = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE,
103 				       obj->uuid, sizeof(TEE_UUID),
104 				       TEE_DATA_FLAG_ACCESS_WRITE_META,
105 				       &obj->attribs_hdl);
106 	if (!res)
107 		TEE_CloseAndDeletePersistentObject1(obj->attribs_hdl);
108 
109 	obj->attribs_hdl = TEE_HANDLE_NULL;
110 	destroy_object_uuid(token, obj);
111 
112 	LIST_REMOVE(obj, link);
113 
114 	cleanup_volatile_obj_ref(obj);
115 }
116 
117 /*
118  * destroy_object - destroy an PKCS11 TA object
119  *
120  * @session - session requesting object destruction
121  * @obj - reference to the PKCS11 TA object
122  * @session_only - true if only session object shall be destroyed
123  */
124 void destroy_object(struct pkcs11_session *session, struct pkcs11_object *obj,
125 		    bool session_only)
126 {
127 #ifdef DEBUG
128 	trace_attributes("[destroy]", obj->attributes);
129 	if (obj->uuid)
130 		MSG_RAW("[destroy] obj uuid %pUl", (void *)obj->uuid);
131 #endif
132 
133 	/*
134 	 * Remove from session list only if it was published.
135 	 *
136 	 * This depends on obj->link.le_prev always pointing on the
137 	 * link.le_next element in the previous object in the list even if
138 	 * there's only a single object in the list. In the first object in
139 	 * the list obj->link.le_prev instead points to lh_first in the
140 	 * list head. If list implementation is changed we need to revisit
141 	 * this.
142 	 */
143 	if (obj->link.le_next || obj->link.le_prev)
144 		LIST_REMOVE(obj, link);
145 
146 	if (session_only) {
147 		/* Destroy object due to session closure */
148 		handle_put(get_object_handle_db(session),
149 			   pkcs11_object2handle(obj, session));
150 		cleanup_volatile_obj_ref(obj);
151 
152 		return;
153 	}
154 
155 	/* Destroy target object (persistent or not) */
156 	if (get_bool(obj->attributes, PKCS11_CKA_TOKEN)) {
157 		assert(obj->uuid);
158 		/* Try twice otherwise panic! */
159 		if (unregister_persistent_object(session->token, obj->uuid) &&
160 		    unregister_persistent_object(session->token, obj->uuid))
161 			TEE_Panic(0);
162 
163 		handle_put(get_object_handle_db(session),
164 			   pkcs11_object2handle(obj, session));
165 		cleanup_persistent_object(obj, session->token);
166 	} else {
167 		handle_put(get_object_handle_db(session),
168 			   pkcs11_object2handle(obj, session));
169 		cleanup_volatile_obj_ref(obj);
170 	}
171 }
172 
173 static struct pkcs11_object *create_obj_instance(struct obj_attrs *head,
174 						 struct ck_token *token)
175 {
176 	struct pkcs11_object *obj = NULL;
177 
178 	obj = TEE_Malloc(sizeof(struct pkcs11_object), TEE_MALLOC_FILL_ZERO);
179 	if (!obj)
180 		return NULL;
181 
182 	obj->key_handle = TEE_HANDLE_NULL;
183 	obj->attribs_hdl = TEE_HANDLE_NULL;
184 	obj->attributes = head;
185 	obj->token = token;
186 
187 	return obj;
188 }
189 
190 struct pkcs11_object *create_token_object(struct obj_attrs *head,
191 					  TEE_UUID *uuid,
192 					  struct ck_token *token)
193 {
194 	struct pkcs11_object *obj = create_obj_instance(head, token);
195 
196 	if (obj)
197 		obj->uuid = uuid;
198 
199 	return obj;
200 }
201 
202 /*
203  * create_object - create an PKCS11 TA object from its attributes and value
204  *
205  * @sess - session requesting object creation
206  * @head - reference to serialized attributes
207  * @out_handle - generated handle for the created object
208  */
209 enum pkcs11_rc create_object(void *sess, struct obj_attrs *head,
210 			     uint32_t *out_handle)
211 {
212 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
213 	struct pkcs11_object *obj = NULL;
214 	struct pkcs11_session *session = (struct pkcs11_session *)sess;
215 	uint32_t obj_handle = 0;
216 
217 #ifdef DEBUG
218 	trace_attributes("[create]", head);
219 #endif
220 
221 	/*
222 	 * We do not check the key attributes. At this point, key attributes
223 	 * are expected consistent and reliable.
224 	 */
225 
226 	obj = create_obj_instance(head, NULL);
227 	if (!obj)
228 		return PKCS11_CKR_DEVICE_MEMORY;
229 
230 	/* Create a handle for the object in the session database */
231 	obj_handle = handle_get(get_object_handle_db(session), obj);
232 	if (!obj_handle) {
233 		rc = PKCS11_CKR_DEVICE_MEMORY;
234 		goto err;
235 	}
236 
237 	if (get_bool(obj->attributes, PKCS11_CKA_TOKEN)) {
238 		TEE_Result res = TEE_SUCCESS;
239 
240 		/*
241 		 * Get an ID for the persistent object
242 		 * Create the file
243 		 * Register the object in the persistent database
244 		 * (move the full sequence to persisent_db.c?)
245 		 */
246 		size_t size = sizeof(struct obj_attrs) +
247 			      obj->attributes->attrs_size;
248 		uint32_t tee_obj_flags = TEE_DATA_FLAG_ACCESS_READ |
249 					 TEE_DATA_FLAG_ACCESS_WRITE |
250 					 TEE_DATA_FLAG_ACCESS_WRITE_META;
251 
252 		rc = create_object_uuid(get_session_token(session), obj);
253 		if (rc)
254 			goto err;
255 
256 		res = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE,
257 						 obj->uuid, sizeof(TEE_UUID),
258 						 tee_obj_flags,
259 						 TEE_HANDLE_NULL,
260 						 obj->attributes, size,
261 						 &obj->attribs_hdl);
262 		if (res) {
263 			rc = tee2pkcs_error(res);
264 			goto err;
265 		}
266 
267 		rc = register_persistent_object(get_session_token(session),
268 						obj->uuid);
269 		if (rc)
270 			goto err;
271 
272 		TEE_CloseObject(obj->attribs_hdl);
273 		obj->attribs_hdl = TEE_HANDLE_NULL;
274 
275 		LIST_INSERT_HEAD(&session->token->object_list, obj, link);
276 	} else {
277 		rc = PKCS11_CKR_OK;
278 		LIST_INSERT_HEAD(get_session_objects(session), obj, link);
279 	}
280 
281 	*out_handle = obj_handle;
282 
283 	return PKCS11_CKR_OK;
284 err:
285 	/* make sure that supplied "head" isn't freed */
286 	obj->attributes = NULL;
287 	handle_put(get_object_handle_db(session), obj_handle);
288 	if (get_bool(head, PKCS11_CKA_TOKEN))
289 		cleanup_persistent_object(obj, session->token);
290 	else
291 		cleanup_volatile_obj_ref(obj);
292 
293 	return rc;
294 }
295 
296 enum pkcs11_rc entry_create_object(struct pkcs11_client *client,
297 				   uint32_t ptypes, TEE_Param *params)
298 {
299 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
300 						TEE_PARAM_TYPE_NONE,
301 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
302 						TEE_PARAM_TYPE_NONE);
303 	enum pkcs11_rc rc = PKCS11_CKR_OK;
304 	TEE_Param *ctrl = params;
305 	TEE_Param *out = params + 2;
306 	struct serialargs ctrlargs = { };
307 	struct pkcs11_session *session = NULL;
308 	struct obj_attrs *head = NULL;
309 	struct pkcs11_object_head *template = NULL;
310 	size_t template_size = 0;
311 	uint32_t obj_handle = 0;
312 
313 	/*
314 	 * Collect the arguments of the request
315 	 */
316 
317 	if (!client || ptypes != exp_pt ||
318 	    out->memref.size != sizeof(obj_handle))
319 		return PKCS11_CKR_ARGUMENTS_BAD;
320 
321 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
322 
323 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
324 	if (rc)
325 		return rc;
326 
327 	rc = serialargs_alloc_get_attributes(&ctrlargs, &template);
328 	if (rc)
329 		return rc;
330 
331 	if (serialargs_remaining_bytes(&ctrlargs)) {
332 		rc = PKCS11_CKR_ARGUMENTS_BAD;
333 		goto out;
334 	}
335 
336 	template_size = sizeof(*template) + template->attrs_size;
337 
338 	/*
339 	 * Prepare a clean initial state for the requested object attributes.
340 	 * Free temporary template once done.
341 	 */
342 	rc = create_attributes_from_template(&head, template, template_size,
343 					     NULL, PKCS11_FUNCTION_IMPORT,
344 					     PKCS11_PROCESSING_IMPORT,
345 					     PKCS11_CKO_UNDEFINED_ID);
346 	TEE_Free(template);
347 	template = NULL;
348 	if (rc)
349 		goto out;
350 
351 	/*
352 	 * Check target object attributes match target processing
353 	 * Check target object attributes match token state
354 	 */
355 	rc = check_created_attrs_against_processing(PKCS11_PROCESSING_IMPORT,
356 						    head);
357 	if (rc)
358 		goto out;
359 
360 	rc = check_created_attrs_against_token(session, head);
361 	if (rc)
362 		goto out;
363 
364 	rc = check_access_attrs_against_token(session, head);
365 	if (rc)
366 		goto out;
367 
368 	/*
369 	 * At this stage the object is almost created: all its attributes are
370 	 * referenced in @head, including the key value and are assumed
371 	 * reliable. Now need to register it and get a handle for it.
372 	 */
373 	rc = create_object(session, head, &obj_handle);
374 	if (rc)
375 		goto out;
376 
377 	/*
378 	 * Now obj_handle (through the related struct pkcs11_object
379 	 * instance) owns the serialized buffer that holds the object
380 	 * attributes. We clear reference in head to NULL as the serializer
381 	 * object is now referred from obj_handle. This allows smooth pass
382 	 * through free at function exit.
383 	 */
384 	head = NULL;
385 
386 	TEE_MemMove(out->memref.buffer, &obj_handle, sizeof(obj_handle));
387 	out->memref.size = sizeof(obj_handle);
388 
389 	DMSG("PKCS11 session %"PRIu32": import object %#"PRIx32,
390 	     session->handle, obj_handle);
391 
392 out:
393 	TEE_Free(template);
394 	TEE_Free(head);
395 
396 	return rc;
397 }
398 
399 enum pkcs11_rc entry_destroy_object(struct pkcs11_client *client,
400 				    uint32_t ptypes, TEE_Param *params)
401 {
402 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
403 						TEE_PARAM_TYPE_NONE,
404 						TEE_PARAM_TYPE_NONE,
405 						TEE_PARAM_TYPE_NONE);
406 	enum pkcs11_rc rc = PKCS11_CKR_OK;
407 	TEE_Param *ctrl = params;
408 	struct serialargs ctrlargs = { };
409 	uint32_t object_handle = 0;
410 	struct pkcs11_session *session = NULL;
411 	struct pkcs11_object *object = NULL;
412 
413 	if (!client || ptypes != exp_pt)
414 		return PKCS11_CKR_ARGUMENTS_BAD;
415 
416 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
417 
418 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
419 	if (rc)
420 		return rc;
421 
422 	rc = serialargs_get_u32(&ctrlargs, &object_handle);
423 	if (rc)
424 		return rc;
425 
426 	if (serialargs_remaining_bytes(&ctrlargs))
427 		return PKCS11_CKR_ARGUMENTS_BAD;
428 
429 	object = pkcs11_handle2object(object_handle, session);
430 	if (!object)
431 		return PKCS11_CKR_OBJECT_HANDLE_INVALID;
432 
433 	/* Only session objects can be destroyed during a read-only session */
434 	if (get_bool(object->attributes, PKCS11_CKA_TOKEN) &&
435 	    !pkcs11_session_is_read_write(session)) {
436 		DMSG("Can't destroy persistent object");
437 		return PKCS11_CKR_SESSION_READ_ONLY;
438 	}
439 
440 	/*
441 	 * Only public objects can be destroyed unless normal user is logged in
442 	 */
443 	rc = check_access_attrs_against_token(session, object->attributes);
444 	if (rc)
445 		return PKCS11_CKR_USER_NOT_LOGGED_IN;
446 
447 	/* Objects with PKCS11_CKA_DESTROYABLE as false aren't destroyable */
448 	if (!get_bool(object->attributes, PKCS11_CKA_DESTROYABLE))
449 		return PKCS11_CKR_ACTION_PROHIBITED;
450 
451 	destroy_object(session, object, false);
452 
453 	DMSG("PKCS11 session %"PRIu32": destroy object %#"PRIx32,
454 	     session->handle, object_handle);
455 
456 	return rc;
457 }
458 
459 static void release_find_obj_context(struct pkcs11_find_objects *find_ctx)
460 {
461 	if (!find_ctx)
462 		return;
463 
464 	TEE_Free(find_ctx->attributes);
465 	TEE_Free(find_ctx->handles);
466 	TEE_Free(find_ctx);
467 }
468 
469 static enum pkcs11_rc find_ctx_add(struct pkcs11_find_objects *find_ctx,
470 				   uint32_t handle)
471 {
472 	uint32_t *hdls = TEE_Realloc(find_ctx->handles,
473 				     (find_ctx->count + 1) * sizeof(*hdls));
474 
475 	if (!hdls)
476 		return PKCS11_CKR_DEVICE_MEMORY;
477 
478 	find_ctx->handles = hdls;
479 
480 	*(find_ctx->handles + find_ctx->count) = handle;
481 	find_ctx->count++;
482 
483 	return PKCS11_CKR_OK;
484 }
485 
486 enum pkcs11_rc entry_find_objects_init(struct pkcs11_client *client,
487 				       uint32_t ptypes, TEE_Param *params)
488 {
489 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
490 						TEE_PARAM_TYPE_NONE,
491 						TEE_PARAM_TYPE_NONE,
492 						TEE_PARAM_TYPE_NONE);
493 	TEE_Param *ctrl = params;
494 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
495 	struct serialargs ctrlargs = { };
496 	struct pkcs11_session *session = NULL;
497 	struct pkcs11_session *sess = NULL;
498 	struct pkcs11_object_head *template = NULL;
499 	struct obj_attrs *req_attrs = NULL;
500 	struct pkcs11_object *obj = NULL;
501 	struct pkcs11_find_objects *find_ctx = NULL;
502 	struct handle_db *object_db = NULL;
503 
504 	if (!client || ptypes != exp_pt)
505 		return PKCS11_CKR_ARGUMENTS_BAD;
506 
507 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
508 
509 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
510 	if (rc)
511 		return rc;
512 
513 	rc = serialargs_alloc_get_attributes(&ctrlargs, &template);
514 	if (rc)
515 		return rc;
516 
517 	if (serialargs_remaining_bytes(&ctrlargs)) {
518 		rc = PKCS11_CKR_ARGUMENTS_BAD;
519 		goto out;
520 	}
521 
522 	/* Search objects only if no operation is on-going */
523 	if (session_is_active(session)) {
524 		rc = PKCS11_CKR_OPERATION_ACTIVE;
525 		goto out;
526 	}
527 
528 	if (session->find_ctx) {
529 		EMSG("Active object search already in progress");
530 		rc = PKCS11_CKR_FUNCTION_FAILED;
531 		goto out;
532 	}
533 
534 	rc = sanitize_client_object(&req_attrs, template,
535 				    sizeof(*template) + template->attrs_size,
536 				    PKCS11_UNDEFINED_ID, PKCS11_UNDEFINED_ID);
537 	if (rc)
538 		goto out;
539 
540 	/* Must zero init the structure */
541 	find_ctx = TEE_Malloc(sizeof(*find_ctx), TEE_MALLOC_FILL_ZERO);
542 	if (!find_ctx) {
543 		rc = PKCS11_CKR_DEVICE_MEMORY;
544 		goto out;
545 	}
546 
547 	TEE_Free(template);
548 	template = NULL;
549 
550 	switch (get_class(req_attrs)) {
551 	case PKCS11_CKO_UNDEFINED_ID:
552 	/* Unspecified class searches among data objects */
553 	case PKCS11_CKO_SECRET_KEY:
554 	case PKCS11_CKO_PUBLIC_KEY:
555 	case PKCS11_CKO_PRIVATE_KEY:
556 	case PKCS11_CKO_DATA:
557 		break;
558 	default:
559 		EMSG("Find object of class %s (%"PRIu32") is not supported",
560 		     id2str_class(get_class(req_attrs)),
561 		     get_class(req_attrs));
562 		rc = PKCS11_CKR_ARGUMENTS_BAD;
563 		goto out;
564 	}
565 
566 	/*
567 	 * Scan all objects (sessions and persistent ones) and set a list of
568 	 * candidates that match caller attributes.
569 	 */
570 
571 	/* Scan all session objects first */
572 	TAILQ_FOREACH(sess, get_session_list(session), link) {
573 		LIST_FOREACH(obj, &sess->object_list, link) {
574 			/*
575 			 * Skip all token objects as they could be from
576 			 * different token which the session does not have
577 			 * access
578 			 */
579 			if (obj->token)
580 				continue;
581 
582 			if (!attributes_match_reference(obj->attributes,
583 							req_attrs))
584 				continue;
585 
586 			rc = find_ctx_add(find_ctx,
587 					  pkcs11_object2handle(obj, session));
588 			if (rc)
589 				goto out;
590 		}
591 	}
592 
593 	object_db = get_object_handle_db(session);
594 
595 	/* Scan token objects */
596 	LIST_FOREACH(obj, &session->token->object_list, link) {
597 		uint32_t handle = 0;
598 		bool new_load = false;
599 
600 		if (!obj->attributes) {
601 			rc = load_persistent_object_attributes(obj);
602 			if (rc)
603 				return PKCS11_CKR_GENERAL_ERROR;
604 
605 			new_load = true;
606 		}
607 
608 		if (!obj->attributes ||
609 		    check_access_attrs_against_token(session,
610 						     obj->attributes) ||
611 		    !attributes_match_reference(obj->attributes, req_attrs)) {
612 			if (new_load)
613 				release_persistent_object_attributes(obj);
614 
615 			continue;
616 		}
617 
618 		/* Resolve object handle for object */
619 		handle = pkcs11_object2handle(obj, session);
620 		if (!handle) {
621 			handle = handle_get(object_db, obj);
622 			if (!handle) {
623 				rc = PKCS11_CKR_DEVICE_MEMORY;
624 				goto out;
625 			}
626 		}
627 
628 		rc = find_ctx_add(find_ctx, handle);
629 		if (rc)
630 			goto out;
631 	}
632 
633 	find_ctx->attributes = req_attrs;
634 	req_attrs = NULL;
635 	session->find_ctx = find_ctx;
636 	find_ctx = NULL;
637 	rc = PKCS11_CKR_OK;
638 
639 out:
640 	TEE_Free(req_attrs);
641 	TEE_Free(template);
642 	release_find_obj_context(find_ctx);
643 
644 	return rc;
645 }
646 
647 enum pkcs11_rc entry_find_objects(struct pkcs11_client *client,
648 				  uint32_t ptypes, TEE_Param *params)
649 {
650 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
651 						TEE_PARAM_TYPE_NONE,
652 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
653 						TEE_PARAM_TYPE_NONE);
654 	TEE_Param *ctrl = params;
655 	TEE_Param *out = params + 2;
656 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
657 	struct serialargs ctrlargs = { };
658 	struct pkcs11_session *session = NULL;
659 	struct pkcs11_find_objects *ctx = NULL;
660 	uint8_t *out_handles = NULL;
661 	size_t out_count = 0;
662 	size_t count = 0;
663 
664 	if (!client || ptypes != exp_pt)
665 		return PKCS11_CKR_ARGUMENTS_BAD;
666 
667 	out_count = out->memref.size / sizeof(uint32_t);
668 	out_handles = out->memref.buffer;
669 
670 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
671 
672 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
673 	if (rc)
674 		return rc;
675 
676 	if (serialargs_remaining_bytes(&ctrlargs))
677 		return PKCS11_CKR_ARGUMENTS_BAD;
678 
679 	ctx = session->find_ctx;
680 
681 	if (!ctx)
682 		return PKCS11_CKR_OPERATION_NOT_INITIALIZED;
683 
684 	for (count = 0; ctx->next < ctx->count && count < out_count;
685 	     ctx->next++, count++)
686 		TEE_MemMove(out_handles + count * sizeof(uint32_t),
687 			    ctx->handles + ctx->next, sizeof(uint32_t));
688 
689 	/* Update output buffer according the number of handles provided */
690 	out->memref.size = count * sizeof(uint32_t);
691 
692 	DMSG("PKCS11 session %"PRIu32": finding objects", session->handle);
693 
694 	return PKCS11_CKR_OK;
695 }
696 
697 void release_session_find_obj_context(struct pkcs11_session *session)
698 {
699 	release_find_obj_context(session->find_ctx);
700 	session->find_ctx = NULL;
701 }
702 
703 enum pkcs11_rc entry_find_objects_final(struct pkcs11_client *client,
704 					uint32_t ptypes, TEE_Param *params)
705 {
706 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
707 						TEE_PARAM_TYPE_NONE,
708 						TEE_PARAM_TYPE_NONE,
709 						TEE_PARAM_TYPE_NONE);
710 	TEE_Param *ctrl = params;
711 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
712 	struct serialargs ctrlargs = { };
713 	struct pkcs11_session *session = NULL;
714 
715 	if (!client || ptypes != exp_pt)
716 		return PKCS11_CKR_ARGUMENTS_BAD;
717 
718 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
719 
720 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
721 	if (rc)
722 		return rc;
723 
724 	if (serialargs_remaining_bytes(&ctrlargs))
725 		return PKCS11_CKR_ARGUMENTS_BAD;
726 
727 	if (!session->find_ctx)
728 		return PKCS11_CKR_OPERATION_NOT_INITIALIZED;
729 
730 	release_session_find_obj_context(session);
731 
732 	return PKCS11_CKR_OK;
733 }
734 
735 enum pkcs11_rc entry_get_attribute_value(struct pkcs11_client *client,
736 					 uint32_t ptypes, TEE_Param *params)
737 {
738 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
739 						TEE_PARAM_TYPE_NONE,
740 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
741 						TEE_PARAM_TYPE_NONE);
742 	TEE_Param *ctrl = params;
743 	TEE_Param *out = params + 2;
744 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
745 	struct serialargs ctrlargs = { };
746 	struct pkcs11_session *session = NULL;
747 	struct pkcs11_object_head *template = NULL;
748 	struct pkcs11_object *obj = NULL;
749 	uint32_t object_handle = 0;
750 	char *cur = NULL;
751 	size_t len = 0;
752 	char *end = NULL;
753 	bool attr_sensitive = 0;
754 	bool attr_type_invalid = 0;
755 	bool buffer_too_small = 0;
756 
757 	if (!client || ptypes != exp_pt)
758 		return PKCS11_CKR_ARGUMENTS_BAD;
759 
760 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
761 
762 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
763 	if (rc)
764 		return rc;
765 
766 	rc = serialargs_get(&ctrlargs, &object_handle, sizeof(uint32_t));
767 	if (rc)
768 		return rc;
769 
770 	rc = serialargs_alloc_get_attributes(&ctrlargs, &template);
771 	if (rc)
772 		return rc;
773 
774 	if (serialargs_remaining_bytes(&ctrlargs)) {
775 		rc = PKCS11_CKR_ARGUMENTS_BAD;
776 		goto out;
777 	}
778 
779 	obj = pkcs11_handle2object(object_handle, session);
780 	if (!obj) {
781 		rc = PKCS11_CKR_OBJECT_HANDLE_INVALID;
782 		goto out;
783 	}
784 
785 	rc = check_access_attrs_against_token(session, obj->attributes);
786 	if (rc) {
787 		rc = PKCS11_CKR_OBJECT_HANDLE_INVALID;
788 		goto out;
789 	}
790 
791 	/* Iterate over attributes and set their values */
792 	/*
793 	 * 1. If the specified attribute (i.e., the attribute specified by the
794 	 * type field) for the object cannot be revealed because the object is
795 	 * sensitive or unextractable, then the ulValueLen field in that triple
796 	 * is modified to hold the value PKCS11_CK_UNAVAILABLE_INFORMATION.
797 	 *
798 	 * 2. Otherwise, if the specified value for the object is invalid (the
799 	 * object does not possess such an attribute), then the ulValueLen field
800 	 * in that triple is modified to hold the value
801 	 * PKCS11_CK_UNAVAILABLE_INFORMATION.
802 	 *
803 	 * 3. Otherwise, if the pValue field has the value NULL_PTR, then the
804 	 * ulValueLen field is modified to hold the exact length of the
805 	 * specified attribute for the object.
806 	 *
807 	 * 4. Otherwise, if the length specified in ulValueLen is large enough
808 	 * to hold the value of the specified attribute for the object, then
809 	 * that attribute is copied into the buffer located at pValue, and the
810 	 * ulValueLen field is modified to hold the exact length of the
811 	 * attribute.
812 	 *
813 	 * 5. Otherwise, the ulValueLen field is modified to hold the value
814 	 * PKCS11_CK_UNAVAILABLE_INFORMATION.
815 	 */
816 	cur = (char *)template + sizeof(struct pkcs11_object_head);
817 	end = cur + template->attrs_size;
818 
819 	for (; cur < end; cur += len) {
820 		struct pkcs11_attribute_head *cli_ref = (void *)cur;
821 		struct pkcs11_attribute_head cli_head = { };
822 		void *data_ptr = NULL;
823 
824 		/* Make copy of header so that is aligned properly. */
825 		TEE_MemMove(&cli_head, cli_ref, sizeof(cli_head));
826 
827 		len = sizeof(*cli_ref) + cli_head.size;
828 
829 		/* We don't support getting value of indirect templates */
830 		if (pkcs11_attr_has_indirect_attributes(cli_head.id)) {
831 			attr_type_invalid = 1;
832 			continue;
833 		}
834 
835 		/* Check 1. */
836 		if (!attribute_is_exportable(&cli_head, obj)) {
837 			cli_head.size = PKCS11_CK_UNAVAILABLE_INFORMATION;
838 			TEE_MemMove(&cli_ref->size, &cli_head.size,
839 				    sizeof(cli_head.size));
840 			attr_sensitive = 1;
841 			continue;
842 		}
843 
844 		/* Get real data pointer from template data */
845 		data_ptr = cli_head.size ? cli_ref->data : NULL;
846 
847 		/*
848 		 * We assume that if size is 0, pValue was NULL, so we return
849 		 * the size of the required buffer for it (3., 4.)
850 		 */
851 		rc = get_attribute(obj->attributes, cli_head.id, data_ptr,
852 				   &cli_head.size);
853 		/* Check 2. */
854 		switch (rc) {
855 		case PKCS11_CKR_OK:
856 			break;
857 		case PKCS11_RV_NOT_FOUND:
858 			cli_head.size = PKCS11_CK_UNAVAILABLE_INFORMATION;
859 			attr_type_invalid = 1;
860 			break;
861 		case PKCS11_CKR_BUFFER_TOO_SMALL:
862 			if (data_ptr)
863 				buffer_too_small = 1;
864 			break;
865 		default:
866 			rc = PKCS11_CKR_GENERAL_ERROR;
867 			goto out;
868 		}
869 
870 		TEE_MemMove(&cli_ref->size, &cli_head.size,
871 			    sizeof(cli_head.size));
872 	}
873 
874 	/*
875 	 * If case 1 applies to any of the requested attributes, then the call
876 	 * should return the value CKR_ATTRIBUTE_SENSITIVE. If case 2 applies to
877 	 * any of the requested attributes, then the call should return the
878 	 * value CKR_ATTRIBUTE_TYPE_INVALID. If case 5 applies to any of the
879 	 * requested attributes, then the call should return the value
880 	 * CKR_BUFFER_TOO_SMALL. As usual, if more than one of these error codes
881 	 * is applicable, Cryptoki may return any of them. Only if none of them
882 	 * applies to any of the requested attributes will CKR_OK be returned.
883 	 */
884 
885 	rc = PKCS11_CKR_OK;
886 	if (attr_sensitive)
887 		rc = PKCS11_CKR_ATTRIBUTE_SENSITIVE;
888 	if (attr_type_invalid)
889 		rc = PKCS11_CKR_ATTRIBUTE_TYPE_INVALID;
890 	if (buffer_too_small)
891 		rc = PKCS11_CKR_BUFFER_TOO_SMALL;
892 
893 	/* Move updated template to out buffer */
894 	TEE_MemMove(out->memref.buffer, template, out->memref.size);
895 
896 	DMSG("PKCS11 session %"PRIu32": get attributes %#"PRIx32,
897 	     session->handle, object_handle);
898 
899 out:
900 	TEE_Free(template);
901 
902 	return rc;
903 }
904 
905 enum pkcs11_rc entry_get_object_size(struct pkcs11_client *client,
906 				     uint32_t ptypes, TEE_Param *params)
907 {
908 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
909 						TEE_PARAM_TYPE_NONE,
910 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
911 						TEE_PARAM_TYPE_NONE);
912 	TEE_Param *ctrl = params;
913 	TEE_Param *out = params + 2;
914 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
915 	struct serialargs ctrlargs = { };
916 	struct pkcs11_session *session = NULL;
917 	uint32_t object_handle = 0;
918 	struct pkcs11_object *obj = NULL;
919 	uint32_t obj_size = 0;
920 
921 	if (!client || ptypes != exp_pt)
922 		return PKCS11_CKR_ARGUMENTS_BAD;
923 
924 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
925 
926 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
927 	if (rc)
928 		return rc;
929 
930 	rc = serialargs_get(&ctrlargs, &object_handle, sizeof(uint32_t));
931 	if (rc)
932 		return rc;
933 
934 	if (serialargs_remaining_bytes(&ctrlargs))
935 		return PKCS11_CKR_ARGUMENTS_BAD;
936 
937 	obj = pkcs11_handle2object(object_handle, session);
938 	if (!obj)
939 		return PKCS11_CKR_OBJECT_HANDLE_INVALID;
940 
941 	rc = check_access_attrs_against_token(session, obj->attributes);
942 	if (rc)
943 		return PKCS11_CKR_OBJECT_HANDLE_INVALID;
944 
945 	if (out->memref.size != sizeof(uint32_t))
946 		return PKCS11_CKR_ARGUMENTS_BAD;
947 
948 	obj_size = ((struct obj_attrs *)obj->attributes)->attrs_size +
949 		   sizeof(struct obj_attrs);
950 	TEE_MemMove(out->memref.buffer, &obj_size, sizeof(obj_size));
951 
952 	return PKCS11_CKR_OK;
953 }
954 
955 enum pkcs11_rc entry_set_attribute_value(struct pkcs11_client *client,
956 					 uint32_t ptypes, TEE_Param *params)
957 {
958 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
959 						TEE_PARAM_TYPE_NONE,
960 						TEE_PARAM_TYPE_NONE,
961 						TEE_PARAM_TYPE_NONE);
962 	TEE_Param *ctrl = params;
963 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
964 	struct serialargs ctrlargs = { };
965 	struct pkcs11_session *session = NULL;
966 	struct pkcs11_object_head *template = NULL;
967 	size_t template_size = 0;
968 	struct pkcs11_object *obj = NULL;
969 	struct obj_attrs *head = NULL;
970 	uint32_t object_handle = 0;
971 	enum processing_func function = PKCS11_FUNCTION_MODIFY;
972 
973 	if (!client || ptypes != exp_pt)
974 		return PKCS11_CKR_ARGUMENTS_BAD;
975 
976 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
977 
978 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
979 	if (rc)
980 		return rc;
981 
982 	rc = serialargs_get(&ctrlargs, &object_handle, sizeof(uint32_t));
983 	if (rc)
984 		return rc;
985 
986 	rc = serialargs_alloc_get_attributes(&ctrlargs, &template);
987 	if (rc)
988 		return rc;
989 
990 	if (serialargs_remaining_bytes(&ctrlargs)) {
991 		rc = PKCS11_CKR_ARGUMENTS_BAD;
992 		goto out;
993 	}
994 
995 	obj = pkcs11_handle2object(object_handle, session);
996 	if (!obj) {
997 		rc = PKCS11_CKR_OBJECT_HANDLE_INVALID;
998 		goto out;
999 	}
1000 
1001 	/* Only session objects can be modified during a read-only session */
1002 	if (object_is_token(obj->attributes) &&
1003 	    !pkcs11_session_is_read_write(session)) {
1004 		DMSG("Can't modify persistent object in a RO session");
1005 		rc = PKCS11_CKR_SESSION_READ_ONLY;
1006 		goto out;
1007 	}
1008 
1009 	/*
1010 	 * Only public objects can be modified unless normal user is logged in
1011 	 */
1012 	rc = check_access_attrs_against_token(session, obj->attributes);
1013 	if (rc) {
1014 		rc = PKCS11_CKR_USER_NOT_LOGGED_IN;
1015 		goto out;
1016 	}
1017 
1018 	/* Objects with PKCS11_CKA_MODIFIABLE as false aren't modifiable */
1019 	if (!object_is_modifiable(obj->attributes)) {
1020 		rc = PKCS11_CKR_ACTION_PROHIBITED;
1021 		goto out;
1022 	}
1023 
1024 	template_size = sizeof(*template) + template->attrs_size;
1025 
1026 	/*
1027 	 * Prepare a clean initial state (@head) for the template. Helps in
1028 	 * removing any duplicates or inconsistent values from the
1029 	 * template.
1030 	 */
1031 	rc = create_attributes_from_template(&head, template, template_size,
1032 					     NULL, function,
1033 					     PKCS11_CKM_UNDEFINED_ID,
1034 					     PKCS11_CKO_UNDEFINED_ID);
1035 	if (rc)
1036 		goto out;
1037 
1038 	/* Check the attributes in @head to see if they are modifiable */
1039 	rc = check_attrs_against_modification(session, head, obj, function);
1040 	if (rc)
1041 		goto out;
1042 
1043 	/*
1044 	 * All checks complete. The attributes in @head have been checked and
1045 	 * can now be used to set/modify the object attributes.
1046 	 */
1047 	rc = modify_attributes_list(&obj->attributes, head);
1048 	if (rc)
1049 		goto out;
1050 
1051 	if (get_bool(obj->attributes, PKCS11_CKA_TOKEN)) {
1052 		rc = update_persistent_object_attributes(obj);
1053 		if (rc)
1054 			goto out;
1055 	}
1056 
1057 	DMSG("PKCS11 session %"PRIu32": set attributes %#"PRIx32,
1058 	     session->handle, object_handle);
1059 
1060 out:
1061 	TEE_Free(head);
1062 	TEE_Free(template);
1063 	return rc;
1064 }
1065 
1066 enum pkcs11_rc entry_copy_object(struct pkcs11_client *client, uint32_t ptypes,
1067 				 TEE_Param *params)
1068 {
1069 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
1070 						TEE_PARAM_TYPE_NONE,
1071 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
1072 						TEE_PARAM_TYPE_NONE);
1073 	TEE_Param *ctrl = params;
1074 	TEE_Param *out = params + 2;
1075 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
1076 	struct serialargs ctrlargs = { };
1077 	struct pkcs11_session *session = NULL;
1078 	struct pkcs11_object_head *template = NULL;
1079 	struct obj_attrs *head = NULL;
1080 	struct obj_attrs *head_new = NULL;
1081 	size_t template_size = 0;
1082 	struct pkcs11_object *obj = NULL;
1083 	uint32_t object_handle = 0;
1084 	uint32_t obj_handle = 0;
1085 	enum processing_func function = PKCS11_FUNCTION_COPY;
1086 	enum pkcs11_class_id class = PKCS11_CKO_UNDEFINED_ID;
1087 
1088 	if (!client || ptypes != exp_pt ||
1089 	    out->memref.size != sizeof(obj_handle))
1090 		return PKCS11_CKR_ARGUMENTS_BAD;
1091 
1092 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
1093 
1094 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
1095 	if (rc)
1096 		return rc;
1097 
1098 	rc = serialargs_get(&ctrlargs, &object_handle, sizeof(uint32_t));
1099 	if (rc)
1100 		return rc;
1101 
1102 	rc = serialargs_alloc_get_attributes(&ctrlargs, &template);
1103 	if (rc)
1104 		return rc;
1105 
1106 	if (serialargs_remaining_bytes(&ctrlargs)) {
1107 		rc = PKCS11_CKR_ARGUMENTS_BAD;
1108 		goto out;
1109 	}
1110 
1111 	obj = pkcs11_handle2object(object_handle, session);
1112 	if (!obj) {
1113 		rc = PKCS11_CKR_OBJECT_HANDLE_INVALID;
1114 		goto out;
1115 	}
1116 
1117 	/* Only session objects can be modified during a read-only session */
1118 	if (object_is_token(obj->attributes) &&
1119 	    !pkcs11_session_is_read_write(session)) {
1120 		DMSG("Can't modify persistent object in a RO session");
1121 		rc = PKCS11_CKR_SESSION_READ_ONLY;
1122 		goto out;
1123 	}
1124 
1125 	/*
1126 	 * Only public objects can be modified unless normal user is logged in
1127 	 */
1128 	rc = check_access_attrs_against_token(session, obj->attributes);
1129 	if (rc) {
1130 		rc = PKCS11_CKR_USER_NOT_LOGGED_IN;
1131 		goto out;
1132 	}
1133 
1134 	/* Objects with PKCS11_CKA_COPYABLE as false can't be copied */
1135 	if (!object_is_copyable(obj->attributes)) {
1136 		rc = PKCS11_CKR_ACTION_PROHIBITED;
1137 		goto out;
1138 	}
1139 
1140 	template_size = sizeof(*template) + template->attrs_size;
1141 
1142 	/*
1143 	 * Prepare a clean initial state (@head) for the template. Helps in
1144 	 * removing any duplicates or inconsistent values from the
1145 	 * template.
1146 	 */
1147 	rc = create_attributes_from_template(&head, template, template_size,
1148 					     NULL, function,
1149 					     PKCS11_CKM_UNDEFINED_ID,
1150 					     PKCS11_CKO_UNDEFINED_ID);
1151 	if (rc)
1152 		goto out;
1153 
1154 	/* Check the attributes in @head to see if they are modifiable */
1155 	rc = check_attrs_against_modification(session, head, obj, function);
1156 	if (rc)
1157 		goto out;
1158 
1159 	class = get_class(obj->attributes);
1160 
1161 	if (class == PKCS11_CKO_SECRET_KEY ||
1162 	    class == PKCS11_CKO_PRIVATE_KEY) {
1163 		/*
1164 		 * If CKA_EXTRACTABLE attribute in passed template (@head) is
1165 		 * modified to CKA_FALSE, CKA_NEVER_EXTRACTABLE should also
1166 		 * change to CKA_FALSE in copied obj. So, add it to the
1167 		 * passed template.
1168 		 */
1169 		uint8_t bbool = 0;
1170 		uint32_t size = sizeof(bbool);
1171 
1172 		rc = get_attribute(head, PKCS11_CKA_EXTRACTABLE, &bbool, &size);
1173 		if (!rc && !bbool) {
1174 			rc = add_attribute(&head, PKCS11_CKA_NEVER_EXTRACTABLE,
1175 					   &bbool, sizeof(uint8_t));
1176 			if (rc)
1177 				goto out;
1178 		}
1179 		rc = PKCS11_CKR_OK;
1180 	}
1181 
1182 	/*
1183 	 * All checks have passed. Create a copy of the serialized buffer which
1184 	 * holds the object attributes in @head_new for the new object
1185 	 */
1186 	template_size = sizeof(*obj->attributes) + obj->attributes->attrs_size;
1187 	head_new = TEE_Malloc(template_size, TEE_MALLOC_FILL_ZERO);
1188 	if (!head_new) {
1189 		rc = PKCS11_CKR_DEVICE_MEMORY;
1190 		goto out;
1191 	}
1192 
1193 	TEE_MemMove(head_new, obj->attributes, template_size);
1194 
1195 	/*
1196 	 * Modify the copied attribute @head_new based on the template @head
1197 	 * given by the callee
1198 	 */
1199 	rc = modify_attributes_list(&head_new, head);
1200 	if (rc)
1201 		goto out;
1202 
1203 	/*
1204 	 * At this stage the object is almost created: all its attributes are
1205 	 * referenced in @head_new, including the key value and are assumed
1206 	 * reliable. Now need to register it and get a handle for it.
1207 	 */
1208 	rc = create_object(session, head_new, &obj_handle);
1209 	if (rc)
1210 		goto out;
1211 
1212 	/*
1213 	 * Now obj_handle (through the related struct pkcs11_object
1214 	 * instance) owns the serialized buffer that holds the object
1215 	 * attributes. We clear reference in head to NULL as the serializer
1216 	 * object is now referred from obj_handle. This allows smooth pass
1217 	 * through free at function exit.
1218 	 */
1219 	head_new = NULL;
1220 
1221 	TEE_MemMove(out->memref.buffer, &obj_handle, sizeof(obj_handle));
1222 	out->memref.size = sizeof(obj_handle);
1223 
1224 	DMSG("PKCS11 session %"PRIu32": copy object %#"PRIx32,
1225 	     session->handle, obj_handle);
1226 
1227 out:
1228 	TEE_Free(head_new);
1229 	TEE_Free(head);
1230 	TEE_Free(template);
1231 	return rc;
1232 }
1233