xref: /optee_os/ta/pkcs11/src/object.c (revision 783c1515c2f9b22497651dee269cd849fd908a56)
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 struct pkcs11_object *pkcs11_handle2object(uint32_t handle,
22 					   struct pkcs11_session *session)
23 {
24 	return handle_lookup(&session->object_handle_db, handle);
25 }
26 
27 uint32_t pkcs11_object2handle(struct pkcs11_object *obj,
28 			      struct pkcs11_session *session)
29 {
30 	return handle_lookup_handle(&session->object_handle_db, obj);
31 }
32 
33 /* Currently handle pkcs11 sessions and tokens */
34 
35 static struct object_list *get_session_objects(void *session)
36 {
37 	/* Currently supporting only pkcs11 session */
38 	struct pkcs11_session *ck_session = session;
39 
40 	return pkcs11_get_session_objects(ck_session);
41 }
42 
43 static struct ck_token *get_session_token(void *session)
44 {
45 	struct pkcs11_session *ck_session = session;
46 
47 	return pkcs11_session2token(ck_session);
48 }
49 
50 /* Release resources of a non-persistent object */
51 static void cleanup_volatile_obj_ref(struct pkcs11_object *obj)
52 {
53 	if (!obj)
54 		return;
55 
56 	if (obj->key_handle != TEE_HANDLE_NULL)
57 		TEE_FreeTransientObject(obj->key_handle);
58 
59 	if (obj->attribs_hdl != TEE_HANDLE_NULL)
60 		TEE_CloseObject(obj->attribs_hdl);
61 
62 	TEE_Free(obj->attributes);
63 	TEE_Free(obj->uuid);
64 	TEE_Free(obj);
65 }
66 
67 /* Release resources of a persistent object including volatile resources */
68 void cleanup_persistent_object(struct pkcs11_object *obj,
69 			       struct ck_token *token)
70 {
71 	TEE_Result res = TEE_SUCCESS;
72 
73 	if (!obj)
74 		return;
75 
76 	/* Open handle with write properties to destroy the object */
77 	if (obj->attribs_hdl != TEE_HANDLE_NULL)
78 		TEE_CloseObject(obj->attribs_hdl);
79 
80 	res = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE,
81 				       obj->uuid, sizeof(TEE_UUID),
82 				       TEE_DATA_FLAG_ACCESS_WRITE_META,
83 				       &obj->attribs_hdl);
84 	if (!res)
85 		TEE_CloseAndDeletePersistentObject1(obj->attribs_hdl);
86 
87 	obj->attribs_hdl = TEE_HANDLE_NULL;
88 	destroy_object_uuid(token, obj);
89 
90 	LIST_REMOVE(obj, link);
91 
92 	cleanup_volatile_obj_ref(obj);
93 }
94 
95 /*
96  * destroy_object - destroy an PKCS11 TA object
97  *
98  * @session - session requesting object destruction
99  * @obj - reference to the PKCS11 TA object
100  * @session_only - true if only session object shall be destroyed
101  */
102 void destroy_object(struct pkcs11_session *session, struct pkcs11_object *obj,
103 		    bool session_only)
104 {
105 #ifdef DEBUG
106 	trace_attributes("[destroy]", obj->attributes);
107 	if (obj->uuid)
108 		MSG_RAW("[destroy] obj uuid %pUl", (void *)obj->uuid);
109 #endif
110 
111 	/*
112 	 * Remove from session list only if it was published.
113 	 *
114 	 * This depends on obj->link.le_prev always pointing on the
115 	 * link.le_next element in the previous object in the list even if
116 	 * there's only a single object in the list. In the first object in
117 	 * the list obj->link.le_prev instead points to lh_first in the
118 	 * list head. If list implementation is changed we need to revisit
119 	 * this.
120 	 */
121 	if (obj->link.le_next || obj->link.le_prev)
122 		LIST_REMOVE(obj, link);
123 
124 	if (session_only) {
125 		/* Destroy object due to session closure */
126 		handle_put(&session->object_handle_db,
127 			   pkcs11_object2handle(obj, session));
128 		cleanup_volatile_obj_ref(obj);
129 
130 		return;
131 	}
132 
133 	/* Destroy target object (persistent or not) */
134 	if (get_bool(obj->attributes, PKCS11_CKA_TOKEN)) {
135 		assert(obj->uuid);
136 		/* Try twice otherwise panic! */
137 		if (unregister_persistent_object(session->token, obj->uuid) &&
138 		    unregister_persistent_object(session->token, obj->uuid))
139 			TEE_Panic(0);
140 
141 		handle_put(&session->object_handle_db,
142 			   pkcs11_object2handle(obj, session));
143 		cleanup_persistent_object(obj, session->token);
144 	} else {
145 		handle_put(&session->object_handle_db,
146 			   pkcs11_object2handle(obj, session));
147 		cleanup_volatile_obj_ref(obj);
148 	}
149 }
150 
151 static struct pkcs11_object *create_obj_instance(struct obj_attrs *head)
152 {
153 	struct pkcs11_object *obj = NULL;
154 
155 	obj = TEE_Malloc(sizeof(struct pkcs11_object), TEE_MALLOC_FILL_ZERO);
156 	if (!obj)
157 		return NULL;
158 
159 	obj->key_handle = TEE_HANDLE_NULL;
160 	obj->attribs_hdl = TEE_HANDLE_NULL;
161 	obj->attributes = head;
162 
163 	return obj;
164 }
165 
166 struct pkcs11_object *create_token_object(struct obj_attrs *head,
167 					  TEE_UUID *uuid)
168 {
169 	struct pkcs11_object *obj = create_obj_instance(head);
170 
171 	if (obj)
172 		obj->uuid = uuid;
173 
174 	return obj;
175 }
176 
177 /*
178  * create_object - create an PKCS11 TA object from its attributes and value
179  *
180  * @sess - session requesting object creation
181  * @head - reference to serialized attributes
182  * @out_handle - generated handle for the created object
183  */
184 enum pkcs11_rc create_object(void *sess, struct obj_attrs *head,
185 			     uint32_t *out_handle)
186 {
187 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
188 	struct pkcs11_object *obj = NULL;
189 	struct pkcs11_session *session = (struct pkcs11_session *)sess;
190 	uint32_t obj_handle = 0;
191 
192 #ifdef DEBUG
193 	trace_attributes("[create]", head);
194 #endif
195 
196 	/*
197 	 * We do not check the key attributes. At this point, key attributes
198 	 * are expected consistent and reliable.
199 	 */
200 
201 	obj = create_obj_instance(head);
202 	if (!obj)
203 		return PKCS11_CKR_DEVICE_MEMORY;
204 
205 	/* Create a handle for the object in the session database */
206 	obj_handle = handle_get(&session->object_handle_db, obj);
207 	if (!obj_handle) {
208 		rc = PKCS11_CKR_DEVICE_MEMORY;
209 		goto err;
210 	}
211 
212 	if (get_bool(obj->attributes, PKCS11_CKA_TOKEN)) {
213 		TEE_Result res = TEE_SUCCESS;
214 
215 		/*
216 		 * Get an ID for the persistent object
217 		 * Create the file
218 		 * Register the object in the persistent database
219 		 * (move the full sequence to persisent_db.c?)
220 		 */
221 		size_t size = sizeof(struct obj_attrs) +
222 			      obj->attributes->attrs_size;
223 		uint32_t tee_obj_flags = TEE_DATA_FLAG_ACCESS_READ |
224 					 TEE_DATA_FLAG_ACCESS_WRITE |
225 					 TEE_DATA_FLAG_ACCESS_WRITE_META;
226 
227 		rc = create_object_uuid(get_session_token(session), obj);
228 		if (rc)
229 			goto err;
230 
231 		res = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE,
232 						 obj->uuid, sizeof(TEE_UUID),
233 						 tee_obj_flags,
234 						 TEE_HANDLE_NULL,
235 						 obj->attributes, size,
236 						 &obj->attribs_hdl);
237 		if (res) {
238 			rc = tee2pkcs_error(res);
239 			goto err;
240 		}
241 
242 		rc = register_persistent_object(get_session_token(session),
243 						obj->uuid);
244 		if (rc)
245 			goto err;
246 
247 		LIST_INSERT_HEAD(&session->token->object_list, obj, link);
248 	} else {
249 		rc = PKCS11_CKR_OK;
250 		LIST_INSERT_HEAD(get_session_objects(session), obj, link);
251 	}
252 
253 	*out_handle = obj_handle;
254 
255 	return PKCS11_CKR_OK;
256 err:
257 	/* make sure that supplied "head" isn't freed */
258 	obj->attributes = NULL;
259 	handle_put(&session->object_handle_db, obj_handle);
260 	if (get_bool(head, PKCS11_CKA_TOKEN))
261 		cleanup_persistent_object(obj, session->token);
262 	else
263 		cleanup_volatile_obj_ref(obj);
264 
265 	return rc;
266 }
267 
268 enum pkcs11_rc entry_create_object(struct pkcs11_client *client,
269 				   uint32_t ptypes, TEE_Param *params)
270 {
271 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
272 						TEE_PARAM_TYPE_NONE,
273 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
274 						TEE_PARAM_TYPE_NONE);
275 	enum pkcs11_rc rc = PKCS11_CKR_OK;
276 	TEE_Param *ctrl = params;
277 	TEE_Param *out = params + 2;
278 	struct serialargs ctrlargs = { };
279 	struct pkcs11_session *session = NULL;
280 	struct obj_attrs *head = NULL;
281 	struct pkcs11_object_head *template = NULL;
282 	size_t template_size = 0;
283 	uint32_t obj_handle = 0;
284 
285 	/*
286 	 * Collect the arguments of the request
287 	 */
288 
289 	if (!client || ptypes != exp_pt ||
290 	    out->memref.size != sizeof(obj_handle))
291 		return PKCS11_CKR_ARGUMENTS_BAD;
292 
293 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
294 
295 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
296 	if (rc)
297 		return rc;
298 
299 	rc = serialargs_alloc_get_attributes(&ctrlargs, &template);
300 	if (rc)
301 		return rc;
302 
303 	if (serialargs_remaining_bytes(&ctrlargs)) {
304 		rc = PKCS11_CKR_ARGUMENTS_BAD;
305 		goto out;
306 	}
307 
308 	template_size = sizeof(*template) + template->attrs_size;
309 
310 	/*
311 	 * Prepare a clean initial state for the requested object attributes.
312 	 * Free temporary template once done.
313 	 */
314 	rc = create_attributes_from_template(&head, template, template_size,
315 					     NULL, PKCS11_FUNCTION_IMPORT,
316 					     PKCS11_PROCESSING_IMPORT,
317 					     PKCS11_CKO_UNDEFINED_ID);
318 	TEE_Free(template);
319 	template = NULL;
320 	if (rc)
321 		goto out;
322 
323 	/*
324 	 * Check target object attributes match target processing
325 	 * Check target object attributes match token state
326 	 */
327 	rc = check_created_attrs_against_processing(PKCS11_PROCESSING_IMPORT,
328 						    head);
329 	if (rc)
330 		goto out;
331 
332 	rc = check_created_attrs_against_token(session, head);
333 	if (rc)
334 		goto out;
335 
336 	rc = check_access_attrs_against_token(session, head);
337 	if (rc)
338 		goto out;
339 
340 	/*
341 	 * At this stage the object is almost created: all its attributes are
342 	 * referenced in @head, including the key value and are assumed
343 	 * reliable. Now need to register it and get a handle for it.
344 	 */
345 	rc = create_object(session, head, &obj_handle);
346 	if (rc)
347 		goto out;
348 
349 	/*
350 	 * Now obj_handle (through the related struct pkcs11_object
351 	 * instance) owns the serialised buffer that holds the object
352 	 * attributes. We clear reference in head to NULL as the serializer
353 	 * object is now referred from obj_handle. This allows smooth pass
354 	 * through free at function exit.
355 	 */
356 	head = NULL;
357 
358 	TEE_MemMove(out->memref.buffer, &obj_handle, sizeof(obj_handle));
359 	out->memref.size = sizeof(obj_handle);
360 
361 	DMSG("PKCS11 session %"PRIu32": import object %#"PRIx32,
362 	     session->handle, obj_handle);
363 
364 out:
365 	TEE_Free(template);
366 	TEE_Free(head);
367 
368 	return rc;
369 }
370 
371 enum pkcs11_rc entry_destroy_object(struct pkcs11_client *client,
372 				    uint32_t ptypes, TEE_Param *params)
373 {
374 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
375 						TEE_PARAM_TYPE_NONE,
376 						TEE_PARAM_TYPE_NONE,
377 						TEE_PARAM_TYPE_NONE);
378 	enum pkcs11_rc rc = PKCS11_CKR_OK;
379 	TEE_Param *ctrl = params;
380 	struct serialargs ctrlargs = { };
381 	uint32_t object_handle = 0;
382 	struct pkcs11_session *session = NULL;
383 	struct pkcs11_object *object = NULL;
384 
385 	if (!client || ptypes != exp_pt)
386 		return PKCS11_CKR_ARGUMENTS_BAD;
387 
388 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
389 
390 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
391 	if (rc)
392 		return rc;
393 
394 	rc = serialargs_get_u32(&ctrlargs, &object_handle);
395 	if (rc)
396 		return rc;
397 
398 	if (serialargs_remaining_bytes(&ctrlargs))
399 		return PKCS11_CKR_ARGUMENTS_BAD;
400 
401 	object = pkcs11_handle2object(object_handle, session);
402 	if (!object)
403 		return PKCS11_CKR_OBJECT_HANDLE_INVALID;
404 
405 	/* Only session objects can be destroyed during a read-only session */
406 	if (get_bool(object->attributes, PKCS11_CKA_TOKEN) &&
407 	    !pkcs11_session_is_read_write(session)) {
408 		DMSG("Can't destroy persistent object");
409 		return PKCS11_CKR_SESSION_READ_ONLY;
410 	}
411 
412 	/*
413 	 * Only public objects can be destroyed unless normal user is logged in
414 	 */
415 	rc = check_access_attrs_against_token(session, object->attributes);
416 	if (rc)
417 		return PKCS11_CKR_USER_NOT_LOGGED_IN;
418 
419 	/* Objects with PKCS11_CKA_DESTROYABLE as false aren't destroyable */
420 	if (!get_bool(object->attributes, PKCS11_CKA_DESTROYABLE))
421 		return PKCS11_CKR_ACTION_PROHIBITED;
422 
423 	destroy_object(session, object, false);
424 
425 	DMSG("PKCS11 session %"PRIu32": destroy object %#"PRIx32,
426 	     session->handle, object_handle);
427 
428 	return rc;
429 }
430 
431 static enum pkcs11_rc token_obj_matches_ref(struct obj_attrs *req_attrs,
432 					    struct pkcs11_object *obj)
433 {
434 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
435 	TEE_Result res = TEE_ERROR_GENERIC;
436 	TEE_ObjectHandle hdl = obj->attribs_hdl;
437 	TEE_ObjectInfo info = { };
438 	struct obj_attrs *attr = NULL;
439 	uint32_t read_bytes = 0;
440 
441 	if (obj->attributes) {
442 		if (!attributes_match_reference(obj->attributes, req_attrs))
443 			return PKCS11_RV_NOT_FOUND;
444 
445 		return PKCS11_CKR_OK;
446 	}
447 
448 	if (hdl == TEE_HANDLE_NULL) {
449 		res = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE,
450 					       obj->uuid, sizeof(*obj->uuid),
451 					       TEE_DATA_FLAG_ACCESS_READ,
452 					       &hdl);
453 		if (res) {
454 			EMSG("OpenPersistent failed %#"PRIx32, res);
455 			return tee2pkcs_error(res);
456 		}
457 	}
458 
459 	res = TEE_GetObjectInfo1(hdl, &info);
460 	if (res) {
461 		EMSG("GetObjectInfo failed %#"PRIx32, res);
462 		rc = tee2pkcs_error(res);
463 		goto out;
464 	}
465 
466 	attr = TEE_Malloc(info.dataSize, TEE_MALLOC_FILL_ZERO);
467 	if (!attr) {
468 		rc = PKCS11_CKR_DEVICE_MEMORY;
469 		goto out;
470 	}
471 
472 	res = TEE_ReadObjectData(hdl, attr, info.dataSize, &read_bytes);
473 	if (!res) {
474 		res = TEE_SeekObjectData(hdl, 0, TEE_DATA_SEEK_SET);
475 		if (res)
476 			EMSG("Seek to 0 failed with %#"PRIx32, res);
477 	}
478 
479 	if (res) {
480 		rc = tee2pkcs_error(res);
481 		EMSG("Read %"PRIu32" bytes, failed %#"PRIx32,
482 		     read_bytes, res);
483 		goto out;
484 	}
485 
486 	if (read_bytes != info.dataSize) {
487 		EMSG("Read %"PRIu32" bytes, expected %"PRIu32,
488 		     read_bytes, info.dataSize);
489 		rc = PKCS11_CKR_GENERAL_ERROR;
490 		goto out;
491 	}
492 
493 	if (!attributes_match_reference(attr, req_attrs)) {
494 		rc = PKCS11_RV_NOT_FOUND;
495 		goto out;
496 	}
497 
498 	obj->attributes = attr;
499 	attr = NULL;
500 	obj->attribs_hdl = hdl;
501 	hdl = TEE_HANDLE_NULL;
502 
503 	rc = PKCS11_CKR_OK;
504 
505 out:
506 	TEE_Free(attr);
507 	if (obj->attribs_hdl == TEE_HANDLE_NULL)
508 		TEE_CloseObject(hdl);
509 
510 	return rc;
511 }
512 
513 static void release_find_obj_context(struct pkcs11_find_objects *find_ctx)
514 {
515 	if (!find_ctx)
516 		return;
517 
518 	TEE_Free(find_ctx->attributes);
519 	TEE_Free(find_ctx->handles);
520 	TEE_Free(find_ctx);
521 }
522 
523 static enum pkcs11_rc find_ctx_add(struct pkcs11_find_objects *find_ctx,
524 				   uint32_t handle)
525 {
526 	uint32_t *hdls = TEE_Realloc(find_ctx->handles,
527 				     (find_ctx->count + 1) * sizeof(*hdls));
528 
529 	if (!hdls)
530 		return PKCS11_CKR_DEVICE_MEMORY;
531 
532 	find_ctx->handles = hdls;
533 
534 	*(find_ctx->handles + find_ctx->count) = handle;
535 	find_ctx->count++;
536 
537 	return PKCS11_CKR_OK;
538 }
539 
540 enum pkcs11_rc entry_find_objects_init(struct pkcs11_client *client,
541 				       uint32_t ptypes, TEE_Param *params)
542 {
543 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
544 						TEE_PARAM_TYPE_NONE,
545 						TEE_PARAM_TYPE_NONE,
546 						TEE_PARAM_TYPE_NONE);
547 	TEE_Param *ctrl = params;
548 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
549 	struct serialargs ctrlargs = { };
550 	struct pkcs11_session *session = NULL;
551 	struct pkcs11_object_head *template = NULL;
552 	struct obj_attrs *req_attrs = NULL;
553 	struct pkcs11_object *obj = NULL;
554 	struct pkcs11_find_objects *find_ctx = NULL;
555 
556 	if (!client || ptypes != exp_pt)
557 		return PKCS11_CKR_ARGUMENTS_BAD;
558 
559 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
560 
561 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
562 	if (rc)
563 		return rc;
564 
565 	rc = serialargs_alloc_get_attributes(&ctrlargs, &template);
566 	if (rc)
567 		return rc;
568 
569 	if (serialargs_remaining_bytes(&ctrlargs)) {
570 		rc = PKCS11_CKR_ARGUMENTS_BAD;
571 		goto out;
572 	}
573 
574 	/* Search objects only if no operation is on-going */
575 	if (session_is_active(session)) {
576 		rc = PKCS11_CKR_OPERATION_ACTIVE;
577 		goto out;
578 	}
579 
580 	if (session->find_ctx) {
581 		EMSG("Active object search already in progress");
582 		rc = PKCS11_CKR_FUNCTION_FAILED;
583 		goto out;
584 	}
585 
586 	rc = sanitize_client_object(&req_attrs, template,
587 				    sizeof(*template) + template->attrs_size,
588 				    PKCS11_UNDEFINED_ID, PKCS11_UNDEFINED_ID);
589 	if (rc)
590 		goto out;
591 
592 	/* Must zero init the structure */
593 	find_ctx = TEE_Malloc(sizeof(*find_ctx), TEE_MALLOC_FILL_ZERO);
594 	if (!find_ctx) {
595 		rc = PKCS11_CKR_DEVICE_MEMORY;
596 		goto out;
597 	}
598 
599 	TEE_Free(template);
600 	template = NULL;
601 
602 	switch (get_class(req_attrs)) {
603 	case PKCS11_CKO_UNDEFINED_ID:
604 	/* Unspecified class searches among data objects */
605 	case PKCS11_CKO_SECRET_KEY:
606 	case PKCS11_CKO_PUBLIC_KEY:
607 	case PKCS11_CKO_PRIVATE_KEY:
608 	case PKCS11_CKO_DATA:
609 		break;
610 	default:
611 		EMSG("Find object of class %s (%"PRIu32") is not supported",
612 		     id2str_class(get_class(req_attrs)),
613 		     get_class(req_attrs));
614 		rc = PKCS11_CKR_ARGUMENTS_BAD;
615 		goto out;
616 	}
617 
618 	/*
619 	 * Scan all objects (sessions and persistent ones) and set a list of
620 	 * candidates that match caller attributes.
621 	 */
622 
623 	LIST_FOREACH(obj, &session->object_list, link) {
624 		if (check_access_attrs_against_token(session, obj->attributes))
625 			continue;
626 
627 		if (req_attrs->attrs_count &&
628 		    !attributes_match_reference(obj->attributes, req_attrs))
629 			continue;
630 
631 		rc = find_ctx_add(find_ctx, pkcs11_object2handle(obj, session));
632 		if (rc)
633 			goto out;
634 	}
635 
636 	LIST_FOREACH(obj, &session->token->object_list, link) {
637 		uint32_t handle = 0;
638 
639 		if (check_access_attrs_against_token(session, obj->attributes))
640 			continue;
641 
642 		if (req_attrs->attrs_count) {
643 			rc = token_obj_matches_ref(req_attrs, obj);
644 			if (rc == PKCS11_RV_NOT_FOUND)
645 				continue;
646 			if (rc != PKCS11_CKR_OK)
647 				goto out;
648 		}
649 
650 		/* Object may not yet be published in the session */
651 		handle = pkcs11_object2handle(obj, session);
652 		if (!handle) {
653 			handle = handle_get(&session->object_handle_db, obj);
654 			if (!handle) {
655 				rc = PKCS11_CKR_DEVICE_MEMORY;
656 				goto out;
657 			}
658 		}
659 
660 		rc = find_ctx_add(find_ctx, handle);
661 		if (rc)
662 			goto out;
663 	}
664 
665 	find_ctx->attributes = req_attrs;
666 	req_attrs = NULL;
667 	session->find_ctx = find_ctx;
668 	find_ctx = NULL;
669 	rc = PKCS11_CKR_OK;
670 
671 out:
672 	TEE_Free(req_attrs);
673 	TEE_Free(template);
674 	release_find_obj_context(find_ctx);
675 
676 	return rc;
677 }
678 
679 enum pkcs11_rc entry_find_objects(struct pkcs11_client *client,
680 				  uint32_t ptypes, TEE_Param *params)
681 {
682 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
683 						TEE_PARAM_TYPE_NONE,
684 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
685 						TEE_PARAM_TYPE_NONE);
686 	TEE_Param *ctrl = params;
687 	TEE_Param *out = params + 2;
688 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
689 	struct serialargs ctrlargs = { };
690 	struct pkcs11_session *session = NULL;
691 	struct pkcs11_find_objects *ctx = NULL;
692 	uint8_t *out_handles = NULL;
693 	size_t out_count = 0;
694 	size_t count = 0;
695 
696 	if (!client || ptypes != exp_pt)
697 		return PKCS11_CKR_ARGUMENTS_BAD;
698 
699 	out_count = out->memref.size / sizeof(uint32_t);
700 	out_handles = out->memref.buffer;
701 
702 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
703 
704 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
705 	if (rc)
706 		return rc;
707 
708 	if (serialargs_remaining_bytes(&ctrlargs))
709 		return PKCS11_CKR_ARGUMENTS_BAD;
710 
711 	ctx = session->find_ctx;
712 
713 	if (!ctx)
714 		return PKCS11_CKR_OPERATION_NOT_INITIALIZED;
715 
716 	for (count = 0; ctx->next < ctx->count && count < out_count;
717 	     ctx->next++, count++)
718 		TEE_MemMove(out_handles + count * sizeof(uint32_t),
719 			    ctx->handles + ctx->next, sizeof(uint32_t));
720 
721 	/* Update output buffer according the number of handles provided */
722 	out->memref.size = count * sizeof(uint32_t);
723 
724 	DMSG("PKCS11 session %"PRIu32": finding objects", session->handle);
725 
726 	return PKCS11_CKR_OK;
727 }
728 
729 void release_session_find_obj_context(struct pkcs11_session *session)
730 {
731 	release_find_obj_context(session->find_ctx);
732 	session->find_ctx = NULL;
733 }
734 
735 uint32_t entry_find_objects_final(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_NONE,
741 						TEE_PARAM_TYPE_NONE);
742 	TEE_Param *ctrl = params;
743 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
744 	struct serialargs ctrlargs = { };
745 	struct pkcs11_session *session = NULL;
746 
747 	if (!client || ptypes != exp_pt)
748 		return PKCS11_CKR_ARGUMENTS_BAD;
749 
750 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
751 
752 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
753 	if (rc)
754 		return rc;
755 
756 	if (serialargs_remaining_bytes(&ctrlargs))
757 		return PKCS11_CKR_ARGUMENTS_BAD;
758 
759 	if (!session->find_ctx)
760 		return PKCS11_CKR_OPERATION_NOT_INITIALIZED;
761 
762 	release_session_find_obj_context(session);
763 
764 	return PKCS11_CKR_OK;
765 }
766 
767 uint32_t entry_get_attribute_value(struct pkcs11_client *client,
768 				   uint32_t ptypes, TEE_Param *params)
769 {
770 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
771 						TEE_PARAM_TYPE_NONE,
772 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
773 						TEE_PARAM_TYPE_NONE);
774 	TEE_Param *ctrl = params;
775 	TEE_Param *out = params + 2;
776 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
777 	struct serialargs ctrlargs = { };
778 	struct pkcs11_session *session = NULL;
779 	struct pkcs11_object_head *template = NULL;
780 	struct pkcs11_object *obj = NULL;
781 	uint32_t object_handle = 0;
782 	char *cur = NULL;
783 	size_t len = 0;
784 	char *end = NULL;
785 	bool attr_sensitive = 0;
786 	bool attr_type_invalid = 0;
787 	bool buffer_too_small = 0;
788 
789 	if (!client || ptypes != exp_pt)
790 		return PKCS11_CKR_ARGUMENTS_BAD;
791 
792 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
793 
794 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
795 	if (rc)
796 		return rc;
797 
798 	rc = serialargs_get(&ctrlargs, &object_handle, sizeof(uint32_t));
799 	if (rc)
800 		return rc;
801 
802 	rc = serialargs_alloc_get_attributes(&ctrlargs, &template);
803 	if (rc)
804 		return rc;
805 
806 	if (serialargs_remaining_bytes(&ctrlargs)) {
807 		rc = PKCS11_CKR_ARGUMENTS_BAD;
808 		goto out;
809 	}
810 
811 	obj = pkcs11_handle2object(object_handle, session);
812 	if (!obj) {
813 		rc = PKCS11_CKR_OBJECT_HANDLE_INVALID;
814 		goto out;
815 	}
816 
817 	rc = check_access_attrs_against_token(session, obj->attributes);
818 	if (rc) {
819 		rc = PKCS11_CKR_OBJECT_HANDLE_INVALID;
820 		goto out;
821 	}
822 
823 	/* Iterate over attributes and set their values */
824 	/*
825 	 * 1. If the specified attribute (i.e., the attribute specified by the
826 	 * type field) for the object cannot be revealed because the object is
827 	 * sensitive or unextractable, then the ulValueLen field in that triple
828 	 * is modified to hold the value PKCS11_CK_UNAVAILABLE_INFORMATION.
829 	 *
830 	 * 2. Otherwise, if the specified value for the object is invalid (the
831 	 * object does not possess such an attribute), then the ulValueLen field
832 	 * in that triple is modified to hold the value
833 	 * PKCS11_CK_UNAVAILABLE_INFORMATION.
834 	 *
835 	 * 3. Otherwise, if the pValue field has the value NULL_PTR, then the
836 	 * ulValueLen field is modified to hold the exact length of the
837 	 * specified attribute for the object.
838 	 *
839 	 * 4. Otherwise, if the length specified in ulValueLen is large enough
840 	 * to hold the value of the specified attribute for the object, then
841 	 * that attribute is copied into the buffer located at pValue, and the
842 	 * ulValueLen field is modified to hold the exact length of the
843 	 * attribute.
844 	 *
845 	 * 5. Otherwise, the ulValueLen field is modified to hold the value
846 	 * PKCS11_CK_UNAVAILABLE_INFORMATION.
847 	 */
848 	cur = (char *)template + sizeof(struct pkcs11_object_head);
849 	end = cur + template->attrs_size;
850 
851 	for (; cur < end; cur += len) {
852 		struct pkcs11_attribute_head *cli_ref = (void *)cur;
853 
854 		len = sizeof(*cli_ref) + cli_ref->size;
855 
856 		/* Check 1. */
857 		if (!attribute_is_exportable(cli_ref, obj)) {
858 			cli_ref->size = PKCS11_CK_UNAVAILABLE_INFORMATION;
859 			attr_sensitive = 1;
860 			continue;
861 		}
862 
863 		/*
864 		 * We assume that if size is 0, pValue was NULL, so we return
865 		 * the size of the required buffer for it (3., 4.)
866 		 */
867 		rc = get_attribute(obj->attributes, cli_ref->id,
868 				   cli_ref->size ? cli_ref->data : NULL,
869 				   &cli_ref->size);
870 		/* Check 2. */
871 		switch (rc) {
872 		case PKCS11_CKR_OK:
873 			break;
874 		case PKCS11_RV_NOT_FOUND:
875 			cli_ref->size = PKCS11_CK_UNAVAILABLE_INFORMATION;
876 			attr_type_invalid = 1;
877 			break;
878 		case PKCS11_CKR_BUFFER_TOO_SMALL:
879 			buffer_too_small = 1;
880 			break;
881 		default:
882 			rc = PKCS11_CKR_GENERAL_ERROR;
883 			goto out;
884 		}
885 	}
886 
887 	/*
888 	 * If case 1 applies to any of the requested attributes, then the call
889 	 * should return the value CKR_ATTRIBUTE_SENSITIVE. If case 2 applies to
890 	 * any of the requested attributes, then the call should return the
891 	 * value CKR_ATTRIBUTE_TYPE_INVALID. If case 5 applies to any of the
892 	 * requested attributes, then the call should return the value
893 	 * CKR_BUFFER_TOO_SMALL. As usual, if more than one of these error codes
894 	 * is applicable, Cryptoki may return any of them. Only if none of them
895 	 * applies to any of the requested attributes will CKR_OK be returned.
896 	 */
897 
898 	rc = PKCS11_CKR_OK;
899 	if (attr_sensitive)
900 		rc = PKCS11_CKR_ATTRIBUTE_SENSITIVE;
901 	if (attr_type_invalid)
902 		rc = PKCS11_CKR_ATTRIBUTE_TYPE_INVALID;
903 	if (buffer_too_small)
904 		rc = PKCS11_CKR_BUFFER_TOO_SMALL;
905 
906 	/* Move updated template to out buffer */
907 	TEE_MemMove(out->memref.buffer, template, out->memref.size);
908 
909 	DMSG("PKCS11 session %"PRIu32": get attributes %#"PRIx32,
910 	     session->handle, object_handle);
911 
912 out:
913 	TEE_Free(template);
914 
915 	return rc;
916 }
917 
918 uint32_t entry_get_object_size(struct pkcs11_client *client,
919 			       uint32_t ptypes, TEE_Param *params)
920 {
921 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
922 						TEE_PARAM_TYPE_NONE,
923 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
924 						TEE_PARAM_TYPE_NONE);
925 	TEE_Param *ctrl = params;
926 	TEE_Param *out = params + 2;
927 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
928 	struct serialargs ctrlargs = { };
929 	struct pkcs11_session *session = NULL;
930 	uint32_t object_handle = 0;
931 	struct pkcs11_object *obj = NULL;
932 	uint32_t obj_size = 0;
933 
934 	if (!client || ptypes != exp_pt)
935 		return PKCS11_CKR_ARGUMENTS_BAD;
936 
937 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
938 
939 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
940 	if (rc)
941 		return rc;
942 
943 	rc = serialargs_get(&ctrlargs, &object_handle, sizeof(uint32_t));
944 	if (rc)
945 		return rc;
946 
947 	if (serialargs_remaining_bytes(&ctrlargs))
948 		return PKCS11_CKR_ARGUMENTS_BAD;
949 
950 	obj = pkcs11_handle2object(object_handle, session);
951 	if (!obj)
952 		return PKCS11_CKR_OBJECT_HANDLE_INVALID;
953 
954 	rc = check_access_attrs_against_token(session, obj->attributes);
955 	if (rc)
956 		return PKCS11_CKR_OBJECT_HANDLE_INVALID;
957 
958 	if (out->memref.size != sizeof(uint32_t))
959 		return PKCS11_CKR_ARGUMENTS_BAD;
960 
961 	obj_size = ((struct obj_attrs *)obj->attributes)->attrs_size +
962 		   sizeof(struct obj_attrs);
963 	TEE_MemMove(out->memref.buffer, &obj_size, sizeof(obj_size));
964 
965 	return PKCS11_CKR_OK;
966 }
967