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