xref: /optee_os/ta/pkcs11/src/object.c (revision c185655eafaab6b4b27759812cd6633e1da9db12)
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 		TEE_CloseObject(obj->attribs_hdl);
248 		obj->attribs_hdl = TEE_HANDLE_NULL;
249 
250 		LIST_INSERT_HEAD(&session->token->object_list, obj, link);
251 	} else {
252 		rc = PKCS11_CKR_OK;
253 		LIST_INSERT_HEAD(get_session_objects(session), obj, link);
254 	}
255 
256 	*out_handle = obj_handle;
257 
258 	return PKCS11_CKR_OK;
259 err:
260 	/* make sure that supplied "head" isn't freed */
261 	obj->attributes = NULL;
262 	handle_put(&session->object_handle_db, obj_handle);
263 	if (get_bool(head, PKCS11_CKA_TOKEN))
264 		cleanup_persistent_object(obj, session->token);
265 	else
266 		cleanup_volatile_obj_ref(obj);
267 
268 	return rc;
269 }
270 
271 enum pkcs11_rc entry_create_object(struct pkcs11_client *client,
272 				   uint32_t ptypes, TEE_Param *params)
273 {
274 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
275 						TEE_PARAM_TYPE_NONE,
276 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
277 						TEE_PARAM_TYPE_NONE);
278 	enum pkcs11_rc rc = PKCS11_CKR_OK;
279 	TEE_Param *ctrl = params;
280 	TEE_Param *out = params + 2;
281 	struct serialargs ctrlargs = { };
282 	struct pkcs11_session *session = NULL;
283 	struct obj_attrs *head = NULL;
284 	struct pkcs11_object_head *template = NULL;
285 	size_t template_size = 0;
286 	uint32_t obj_handle = 0;
287 
288 	/*
289 	 * Collect the arguments of the request
290 	 */
291 
292 	if (!client || ptypes != exp_pt ||
293 	    out->memref.size != sizeof(obj_handle))
294 		return PKCS11_CKR_ARGUMENTS_BAD;
295 
296 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
297 
298 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
299 	if (rc)
300 		return rc;
301 
302 	rc = serialargs_alloc_get_attributes(&ctrlargs, &template);
303 	if (rc)
304 		return rc;
305 
306 	if (serialargs_remaining_bytes(&ctrlargs)) {
307 		rc = PKCS11_CKR_ARGUMENTS_BAD;
308 		goto out;
309 	}
310 
311 	template_size = sizeof(*template) + template->attrs_size;
312 
313 	/*
314 	 * Prepare a clean initial state for the requested object attributes.
315 	 * Free temporary template once done.
316 	 */
317 	rc = create_attributes_from_template(&head, template, template_size,
318 					     NULL, PKCS11_FUNCTION_IMPORT,
319 					     PKCS11_PROCESSING_IMPORT,
320 					     PKCS11_CKO_UNDEFINED_ID);
321 	TEE_Free(template);
322 	template = NULL;
323 	if (rc)
324 		goto out;
325 
326 	/*
327 	 * Check target object attributes match target processing
328 	 * Check target object attributes match token state
329 	 */
330 	rc = check_created_attrs_against_processing(PKCS11_PROCESSING_IMPORT,
331 						    head);
332 	if (rc)
333 		goto out;
334 
335 	rc = check_created_attrs_against_token(session, head);
336 	if (rc)
337 		goto out;
338 
339 	rc = check_access_attrs_against_token(session, head);
340 	if (rc)
341 		goto out;
342 
343 	/*
344 	 * At this stage the object is almost created: all its attributes are
345 	 * referenced in @head, including the key value and are assumed
346 	 * reliable. Now need to register it and get a handle for it.
347 	 */
348 	rc = create_object(session, head, &obj_handle);
349 	if (rc)
350 		goto out;
351 
352 	/*
353 	 * Now obj_handle (through the related struct pkcs11_object
354 	 * instance) owns the serialized buffer that holds the object
355 	 * attributes. We clear reference in head to NULL as the serializer
356 	 * object is now referred from obj_handle. This allows smooth pass
357 	 * through free at function exit.
358 	 */
359 	head = NULL;
360 
361 	TEE_MemMove(out->memref.buffer, &obj_handle, sizeof(obj_handle));
362 	out->memref.size = sizeof(obj_handle);
363 
364 	DMSG("PKCS11 session %"PRIu32": import object %#"PRIx32,
365 	     session->handle, obj_handle);
366 
367 out:
368 	TEE_Free(template);
369 	TEE_Free(head);
370 
371 	return rc;
372 }
373 
374 enum pkcs11_rc entry_destroy_object(struct pkcs11_client *client,
375 				    uint32_t ptypes, TEE_Param *params)
376 {
377 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
378 						TEE_PARAM_TYPE_NONE,
379 						TEE_PARAM_TYPE_NONE,
380 						TEE_PARAM_TYPE_NONE);
381 	enum pkcs11_rc rc = PKCS11_CKR_OK;
382 	TEE_Param *ctrl = params;
383 	struct serialargs ctrlargs = { };
384 	uint32_t object_handle = 0;
385 	struct pkcs11_session *session = NULL;
386 	struct pkcs11_object *object = NULL;
387 
388 	if (!client || ptypes != exp_pt)
389 		return PKCS11_CKR_ARGUMENTS_BAD;
390 
391 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
392 
393 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
394 	if (rc)
395 		return rc;
396 
397 	rc = serialargs_get_u32(&ctrlargs, &object_handle);
398 	if (rc)
399 		return rc;
400 
401 	if (serialargs_remaining_bytes(&ctrlargs))
402 		return PKCS11_CKR_ARGUMENTS_BAD;
403 
404 	object = pkcs11_handle2object(object_handle, session);
405 	if (!object)
406 		return PKCS11_CKR_OBJECT_HANDLE_INVALID;
407 
408 	/* Only session objects can be destroyed during a read-only session */
409 	if (get_bool(object->attributes, PKCS11_CKA_TOKEN) &&
410 	    !pkcs11_session_is_read_write(session)) {
411 		DMSG("Can't destroy persistent object");
412 		return PKCS11_CKR_SESSION_READ_ONLY;
413 	}
414 
415 	/*
416 	 * Only public objects can be destroyed unless normal user is logged in
417 	 */
418 	rc = check_access_attrs_against_token(session, object->attributes);
419 	if (rc)
420 		return PKCS11_CKR_USER_NOT_LOGGED_IN;
421 
422 	/* Objects with PKCS11_CKA_DESTROYABLE as false aren't destroyable */
423 	if (!get_bool(object->attributes, PKCS11_CKA_DESTROYABLE))
424 		return PKCS11_CKR_ACTION_PROHIBITED;
425 
426 	destroy_object(session, object, false);
427 
428 	DMSG("PKCS11 session %"PRIu32": destroy object %#"PRIx32,
429 	     session->handle, object_handle);
430 
431 	return rc;
432 }
433 
434 static void release_find_obj_context(struct pkcs11_find_objects *find_ctx)
435 {
436 	if (!find_ctx)
437 		return;
438 
439 	TEE_Free(find_ctx->attributes);
440 	TEE_Free(find_ctx->handles);
441 	TEE_Free(find_ctx);
442 }
443 
444 static enum pkcs11_rc find_ctx_add(struct pkcs11_find_objects *find_ctx,
445 				   uint32_t handle)
446 {
447 	uint32_t *hdls = TEE_Realloc(find_ctx->handles,
448 				     (find_ctx->count + 1) * sizeof(*hdls));
449 
450 	if (!hdls)
451 		return PKCS11_CKR_DEVICE_MEMORY;
452 
453 	find_ctx->handles = hdls;
454 
455 	*(find_ctx->handles + find_ctx->count) = handle;
456 	find_ctx->count++;
457 
458 	return PKCS11_CKR_OK;
459 }
460 
461 enum pkcs11_rc entry_find_objects_init(struct pkcs11_client *client,
462 				       uint32_t ptypes, TEE_Param *params)
463 {
464 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
465 						TEE_PARAM_TYPE_NONE,
466 						TEE_PARAM_TYPE_NONE,
467 						TEE_PARAM_TYPE_NONE);
468 	TEE_Param *ctrl = params;
469 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
470 	struct serialargs ctrlargs = { };
471 	struct pkcs11_session *session = NULL;
472 	struct pkcs11_object_head *template = NULL;
473 	struct obj_attrs *req_attrs = NULL;
474 	struct pkcs11_object *obj = NULL;
475 	struct pkcs11_find_objects *find_ctx = NULL;
476 
477 	if (!client || ptypes != exp_pt)
478 		return PKCS11_CKR_ARGUMENTS_BAD;
479 
480 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
481 
482 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
483 	if (rc)
484 		return rc;
485 
486 	rc = serialargs_alloc_get_attributes(&ctrlargs, &template);
487 	if (rc)
488 		return rc;
489 
490 	if (serialargs_remaining_bytes(&ctrlargs)) {
491 		rc = PKCS11_CKR_ARGUMENTS_BAD;
492 		goto out;
493 	}
494 
495 	/* Search objects only if no operation is on-going */
496 	if (session_is_active(session)) {
497 		rc = PKCS11_CKR_OPERATION_ACTIVE;
498 		goto out;
499 	}
500 
501 	if (session->find_ctx) {
502 		EMSG("Active object search already in progress");
503 		rc = PKCS11_CKR_FUNCTION_FAILED;
504 		goto out;
505 	}
506 
507 	rc = sanitize_client_object(&req_attrs, template,
508 				    sizeof(*template) + template->attrs_size,
509 				    PKCS11_UNDEFINED_ID, PKCS11_UNDEFINED_ID);
510 	if (rc)
511 		goto out;
512 
513 	/* Must zero init the structure */
514 	find_ctx = TEE_Malloc(sizeof(*find_ctx), TEE_MALLOC_FILL_ZERO);
515 	if (!find_ctx) {
516 		rc = PKCS11_CKR_DEVICE_MEMORY;
517 		goto out;
518 	}
519 
520 	TEE_Free(template);
521 	template = NULL;
522 
523 	switch (get_class(req_attrs)) {
524 	case PKCS11_CKO_UNDEFINED_ID:
525 	/* Unspecified class searches among data objects */
526 	case PKCS11_CKO_SECRET_KEY:
527 	case PKCS11_CKO_PUBLIC_KEY:
528 	case PKCS11_CKO_PRIVATE_KEY:
529 	case PKCS11_CKO_DATA:
530 		break;
531 	default:
532 		EMSG("Find object of class %s (%"PRIu32") is not supported",
533 		     id2str_class(get_class(req_attrs)),
534 		     get_class(req_attrs));
535 		rc = PKCS11_CKR_ARGUMENTS_BAD;
536 		goto out;
537 	}
538 
539 	/*
540 	 * Scan all objects (sessions and persistent ones) and set a list of
541 	 * candidates that match caller attributes.
542 	 */
543 
544 	LIST_FOREACH(obj, &session->object_list, link) {
545 		if (check_access_attrs_against_token(session, obj->attributes))
546 			continue;
547 
548 		if (!attributes_match_reference(obj->attributes, req_attrs))
549 			continue;
550 
551 		rc = find_ctx_add(find_ctx, pkcs11_object2handle(obj, session));
552 		if (rc)
553 			goto out;
554 	}
555 
556 	LIST_FOREACH(obj, &session->token->object_list, link) {
557 		uint32_t handle = 0;
558 		bool new_load = false;
559 
560 		if (!obj->attributes) {
561 			rc = load_persistent_object_attributes(obj);
562 			if (rc)
563 				return PKCS11_CKR_GENERAL_ERROR;
564 
565 			new_load = true;
566 		}
567 
568 		if (!obj->attributes ||
569 		    check_access_attrs_against_token(session,
570 						     obj->attributes) ||
571 		    !attributes_match_reference(obj->attributes, req_attrs)) {
572 			if (new_load)
573 				release_persistent_object_attributes(obj);
574 
575 			continue;
576 		}
577 
578 		/* Object may not yet be published in the session */
579 		handle = pkcs11_object2handle(obj, session);
580 		if (!handle) {
581 			handle = handle_get(&session->object_handle_db, obj);
582 			if (!handle) {
583 				rc = PKCS11_CKR_DEVICE_MEMORY;
584 				goto out;
585 			}
586 		}
587 
588 		rc = find_ctx_add(find_ctx, handle);
589 		if (rc)
590 			goto out;
591 	}
592 
593 	find_ctx->attributes = req_attrs;
594 	req_attrs = NULL;
595 	session->find_ctx = find_ctx;
596 	find_ctx = NULL;
597 	rc = PKCS11_CKR_OK;
598 
599 out:
600 	TEE_Free(req_attrs);
601 	TEE_Free(template);
602 	release_find_obj_context(find_ctx);
603 
604 	return rc;
605 }
606 
607 enum pkcs11_rc entry_find_objects(struct pkcs11_client *client,
608 				  uint32_t ptypes, TEE_Param *params)
609 {
610 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
611 						TEE_PARAM_TYPE_NONE,
612 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
613 						TEE_PARAM_TYPE_NONE);
614 	TEE_Param *ctrl = params;
615 	TEE_Param *out = params + 2;
616 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
617 	struct serialargs ctrlargs = { };
618 	struct pkcs11_session *session = NULL;
619 	struct pkcs11_find_objects *ctx = NULL;
620 	uint8_t *out_handles = NULL;
621 	size_t out_count = 0;
622 	size_t count = 0;
623 
624 	if (!client || ptypes != exp_pt)
625 		return PKCS11_CKR_ARGUMENTS_BAD;
626 
627 	out_count = out->memref.size / sizeof(uint32_t);
628 	out_handles = out->memref.buffer;
629 
630 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
631 
632 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
633 	if (rc)
634 		return rc;
635 
636 	if (serialargs_remaining_bytes(&ctrlargs))
637 		return PKCS11_CKR_ARGUMENTS_BAD;
638 
639 	ctx = session->find_ctx;
640 
641 	if (!ctx)
642 		return PKCS11_CKR_OPERATION_NOT_INITIALIZED;
643 
644 	for (count = 0; ctx->next < ctx->count && count < out_count;
645 	     ctx->next++, count++)
646 		TEE_MemMove(out_handles + count * sizeof(uint32_t),
647 			    ctx->handles + ctx->next, sizeof(uint32_t));
648 
649 	/* Update output buffer according the number of handles provided */
650 	out->memref.size = count * sizeof(uint32_t);
651 
652 	DMSG("PKCS11 session %"PRIu32": finding objects", session->handle);
653 
654 	return PKCS11_CKR_OK;
655 }
656 
657 void release_session_find_obj_context(struct pkcs11_session *session)
658 {
659 	release_find_obj_context(session->find_ctx);
660 	session->find_ctx = NULL;
661 }
662 
663 enum pkcs11_rc entry_find_objects_final(struct pkcs11_client *client,
664 					uint32_t ptypes, TEE_Param *params)
665 {
666 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
667 						TEE_PARAM_TYPE_NONE,
668 						TEE_PARAM_TYPE_NONE,
669 						TEE_PARAM_TYPE_NONE);
670 	TEE_Param *ctrl = params;
671 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
672 	struct serialargs ctrlargs = { };
673 	struct pkcs11_session *session = NULL;
674 
675 	if (!client || ptypes != exp_pt)
676 		return PKCS11_CKR_ARGUMENTS_BAD;
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 	if (!session->find_ctx)
688 		return PKCS11_CKR_OPERATION_NOT_INITIALIZED;
689 
690 	release_session_find_obj_context(session);
691 
692 	return PKCS11_CKR_OK;
693 }
694 
695 enum pkcs11_rc entry_get_attribute_value(struct pkcs11_client *client,
696 					 uint32_t ptypes, TEE_Param *params)
697 {
698 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
699 						TEE_PARAM_TYPE_NONE,
700 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
701 						TEE_PARAM_TYPE_NONE);
702 	TEE_Param *ctrl = params;
703 	TEE_Param *out = params + 2;
704 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
705 	struct serialargs ctrlargs = { };
706 	struct pkcs11_session *session = NULL;
707 	struct pkcs11_object_head *template = NULL;
708 	struct pkcs11_object *obj = NULL;
709 	uint32_t object_handle = 0;
710 	char *cur = NULL;
711 	size_t len = 0;
712 	char *end = NULL;
713 	bool attr_sensitive = 0;
714 	bool attr_type_invalid = 0;
715 	bool buffer_too_small = 0;
716 
717 	if (!client || ptypes != exp_pt)
718 		return PKCS11_CKR_ARGUMENTS_BAD;
719 
720 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
721 
722 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
723 	if (rc)
724 		return rc;
725 
726 	rc = serialargs_get(&ctrlargs, &object_handle, sizeof(uint32_t));
727 	if (rc)
728 		return rc;
729 
730 	rc = serialargs_alloc_get_attributes(&ctrlargs, &template);
731 	if (rc)
732 		return rc;
733 
734 	if (serialargs_remaining_bytes(&ctrlargs)) {
735 		rc = PKCS11_CKR_ARGUMENTS_BAD;
736 		goto out;
737 	}
738 
739 	obj = pkcs11_handle2object(object_handle, session);
740 	if (!obj) {
741 		rc = PKCS11_CKR_OBJECT_HANDLE_INVALID;
742 		goto out;
743 	}
744 
745 	rc = check_access_attrs_against_token(session, obj->attributes);
746 	if (rc) {
747 		rc = PKCS11_CKR_OBJECT_HANDLE_INVALID;
748 		goto out;
749 	}
750 
751 	/* Iterate over attributes and set their values */
752 	/*
753 	 * 1. If the specified attribute (i.e., the attribute specified by the
754 	 * type field) for the object cannot be revealed because the object is
755 	 * sensitive or unextractable, then the ulValueLen field in that triple
756 	 * is modified to hold the value PKCS11_CK_UNAVAILABLE_INFORMATION.
757 	 *
758 	 * 2. Otherwise, if the specified value for the object is invalid (the
759 	 * object does not possess such an attribute), then the ulValueLen field
760 	 * in that triple is modified to hold the value
761 	 * PKCS11_CK_UNAVAILABLE_INFORMATION.
762 	 *
763 	 * 3. Otherwise, if the pValue field has the value NULL_PTR, then the
764 	 * ulValueLen field is modified to hold the exact length of the
765 	 * specified attribute for the object.
766 	 *
767 	 * 4. Otherwise, if the length specified in ulValueLen is large enough
768 	 * to hold the value of the specified attribute for the object, then
769 	 * that attribute is copied into the buffer located at pValue, and the
770 	 * ulValueLen field is modified to hold the exact length of the
771 	 * attribute.
772 	 *
773 	 * 5. Otherwise, the ulValueLen field is modified to hold the value
774 	 * PKCS11_CK_UNAVAILABLE_INFORMATION.
775 	 */
776 	cur = (char *)template + sizeof(struct pkcs11_object_head);
777 	end = cur + template->attrs_size;
778 
779 	for (; cur < end; cur += len) {
780 		struct pkcs11_attribute_head *cli_ref = (void *)cur;
781 		struct pkcs11_attribute_head cli_head = { };
782 		void *data_ptr = NULL;
783 
784 		/* Make copy of header so that is aligned properly. */
785 		TEE_MemMove(&cli_head, cli_ref, sizeof(cli_head));
786 
787 		len = sizeof(*cli_ref) + cli_head.size;
788 
789 		/* Check 1. */
790 		if (!attribute_is_exportable(&cli_head, obj)) {
791 			cli_head.size = PKCS11_CK_UNAVAILABLE_INFORMATION;
792 			TEE_MemMove(&cli_ref->size, &cli_head.size,
793 				    sizeof(cli_head.size));
794 			attr_sensitive = 1;
795 			continue;
796 		}
797 
798 		/* Get real data pointer from template data */
799 		data_ptr = cli_head.size ? cli_ref->data : NULL;
800 
801 		/*
802 		 * We assume that if size is 0, pValue was NULL, so we return
803 		 * the size of the required buffer for it (3., 4.)
804 		 */
805 		rc = get_attribute(obj->attributes, cli_head.id, data_ptr,
806 				   &cli_head.size);
807 		/* Check 2. */
808 		switch (rc) {
809 		case PKCS11_CKR_OK:
810 			break;
811 		case PKCS11_RV_NOT_FOUND:
812 			cli_head.size = PKCS11_CK_UNAVAILABLE_INFORMATION;
813 			attr_type_invalid = 1;
814 			break;
815 		case PKCS11_CKR_BUFFER_TOO_SMALL:
816 			if (data_ptr)
817 				buffer_too_small = 1;
818 			break;
819 		default:
820 			rc = PKCS11_CKR_GENERAL_ERROR;
821 			goto out;
822 		}
823 
824 		TEE_MemMove(&cli_ref->size, &cli_head.size,
825 			    sizeof(cli_head.size));
826 	}
827 
828 	/*
829 	 * If case 1 applies to any of the requested attributes, then the call
830 	 * should return the value CKR_ATTRIBUTE_SENSITIVE. If case 2 applies to
831 	 * any of the requested attributes, then the call should return the
832 	 * value CKR_ATTRIBUTE_TYPE_INVALID. If case 5 applies to any of the
833 	 * requested attributes, then the call should return the value
834 	 * CKR_BUFFER_TOO_SMALL. As usual, if more than one of these error codes
835 	 * is applicable, Cryptoki may return any of them. Only if none of them
836 	 * applies to any of the requested attributes will CKR_OK be returned.
837 	 */
838 
839 	rc = PKCS11_CKR_OK;
840 	if (attr_sensitive)
841 		rc = PKCS11_CKR_ATTRIBUTE_SENSITIVE;
842 	if (attr_type_invalid)
843 		rc = PKCS11_CKR_ATTRIBUTE_TYPE_INVALID;
844 	if (buffer_too_small)
845 		rc = PKCS11_CKR_BUFFER_TOO_SMALL;
846 
847 	/* Move updated template to out buffer */
848 	TEE_MemMove(out->memref.buffer, template, out->memref.size);
849 
850 	DMSG("PKCS11 session %"PRIu32": get attributes %#"PRIx32,
851 	     session->handle, object_handle);
852 
853 out:
854 	TEE_Free(template);
855 
856 	return rc;
857 }
858 
859 enum pkcs11_rc entry_get_object_size(struct pkcs11_client *client,
860 				     uint32_t ptypes, TEE_Param *params)
861 {
862 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
863 						TEE_PARAM_TYPE_NONE,
864 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
865 						TEE_PARAM_TYPE_NONE);
866 	TEE_Param *ctrl = params;
867 	TEE_Param *out = params + 2;
868 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
869 	struct serialargs ctrlargs = { };
870 	struct pkcs11_session *session = NULL;
871 	uint32_t object_handle = 0;
872 	struct pkcs11_object *obj = NULL;
873 	uint32_t obj_size = 0;
874 
875 	if (!client || ptypes != exp_pt)
876 		return PKCS11_CKR_ARGUMENTS_BAD;
877 
878 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
879 
880 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
881 	if (rc)
882 		return rc;
883 
884 	rc = serialargs_get(&ctrlargs, &object_handle, sizeof(uint32_t));
885 	if (rc)
886 		return rc;
887 
888 	if (serialargs_remaining_bytes(&ctrlargs))
889 		return PKCS11_CKR_ARGUMENTS_BAD;
890 
891 	obj = pkcs11_handle2object(object_handle, session);
892 	if (!obj)
893 		return PKCS11_CKR_OBJECT_HANDLE_INVALID;
894 
895 	rc = check_access_attrs_against_token(session, obj->attributes);
896 	if (rc)
897 		return PKCS11_CKR_OBJECT_HANDLE_INVALID;
898 
899 	if (out->memref.size != sizeof(uint32_t))
900 		return PKCS11_CKR_ARGUMENTS_BAD;
901 
902 	obj_size = ((struct obj_attrs *)obj->attributes)->attrs_size +
903 		   sizeof(struct obj_attrs);
904 	TEE_MemMove(out->memref.buffer, &obj_size, sizeof(obj_size));
905 
906 	return PKCS11_CKR_OK;
907 }
908 
909 enum pkcs11_rc entry_set_attribute_value(struct pkcs11_client *client,
910 					 uint32_t ptypes, TEE_Param *params)
911 {
912 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
913 						TEE_PARAM_TYPE_NONE,
914 						TEE_PARAM_TYPE_NONE,
915 						TEE_PARAM_TYPE_NONE);
916 	TEE_Param *ctrl = params;
917 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
918 	struct serialargs ctrlargs = { };
919 	struct pkcs11_session *session = NULL;
920 	struct pkcs11_object_head *template = NULL;
921 	size_t template_size = 0;
922 	struct pkcs11_object *obj = NULL;
923 	struct obj_attrs *head = NULL;
924 	uint32_t object_handle = 0;
925 	enum processing_func function = PKCS11_FUNCTION_MODIFY;
926 
927 	if (!client || ptypes != exp_pt)
928 		return PKCS11_CKR_ARGUMENTS_BAD;
929 
930 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
931 
932 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
933 	if (rc)
934 		return rc;
935 
936 	rc = serialargs_get(&ctrlargs, &object_handle, sizeof(uint32_t));
937 	if (rc)
938 		return rc;
939 
940 	rc = serialargs_alloc_get_attributes(&ctrlargs, &template);
941 	if (rc)
942 		return rc;
943 
944 	if (serialargs_remaining_bytes(&ctrlargs)) {
945 		rc = PKCS11_CKR_ARGUMENTS_BAD;
946 		goto out;
947 	}
948 
949 	obj = pkcs11_handle2object(object_handle, session);
950 	if (!obj) {
951 		rc = PKCS11_CKR_OBJECT_HANDLE_INVALID;
952 		goto out;
953 	}
954 
955 	/* Only session objects can be modified during a read-only session */
956 	if (object_is_token(obj->attributes) &&
957 	    !pkcs11_session_is_read_write(session)) {
958 		DMSG("Can't modify persistent object in a RO session");
959 		rc = PKCS11_CKR_SESSION_READ_ONLY;
960 		goto out;
961 	}
962 
963 	/*
964 	 * Only public objects can be modified unless normal user is logged in
965 	 */
966 	rc = check_access_attrs_against_token(session, obj->attributes);
967 	if (rc) {
968 		rc = PKCS11_CKR_USER_NOT_LOGGED_IN;
969 		goto out;
970 	}
971 
972 	/* Objects with PKCS11_CKA_MODIFIABLE as false aren't modifiable */
973 	if (!object_is_modifiable(obj->attributes)) {
974 		rc = PKCS11_CKR_ACTION_PROHIBITED;
975 		goto out;
976 	}
977 
978 	template_size = sizeof(*template) + template->attrs_size;
979 
980 	/*
981 	 * Prepare a clean initial state (@head) for the template. Helps in
982 	 * removing any duplicates or inconsistent values from the
983 	 * template.
984 	 */
985 	rc = create_attributes_from_template(&head, template, template_size,
986 					     NULL, function,
987 					     PKCS11_CKM_UNDEFINED_ID,
988 					     PKCS11_CKO_UNDEFINED_ID);
989 	if (rc)
990 		goto out;
991 
992 	/* Check the attributes in @head to see if they are modifiable */
993 	rc = check_attrs_against_modification(session, head, obj, function);
994 	if (rc)
995 		goto out;
996 
997 	/*
998 	 * All checks complete. The attributes in @head have been checked and
999 	 * can now be used to set/modify the object attributes.
1000 	 */
1001 	rc = modify_attributes_list(&obj->attributes, head);
1002 	if (rc)
1003 		goto out;
1004 
1005 	if (get_bool(obj->attributes, PKCS11_CKA_TOKEN)) {
1006 		rc = update_persistent_object_attributes(obj);
1007 		if (rc)
1008 			goto out;
1009 	}
1010 
1011 	DMSG("PKCS11 session %"PRIu32": set attributes %#"PRIx32,
1012 	     session->handle, object_handle);
1013 
1014 out:
1015 	TEE_Free(head);
1016 	TEE_Free(template);
1017 	return rc;
1018 }
1019 
1020 enum pkcs11_rc entry_copy_object(struct pkcs11_client *client, uint32_t ptypes,
1021 				 TEE_Param *params)
1022 {
1023 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
1024 						TEE_PARAM_TYPE_NONE,
1025 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
1026 						TEE_PARAM_TYPE_NONE);
1027 	TEE_Param *ctrl = params;
1028 	TEE_Param *out = params + 2;
1029 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
1030 	struct serialargs ctrlargs = { };
1031 	struct pkcs11_session *session = NULL;
1032 	struct pkcs11_object_head *template = NULL;
1033 	struct obj_attrs *head = NULL;
1034 	struct obj_attrs *head_new = NULL;
1035 	size_t template_size = 0;
1036 	struct pkcs11_object *obj = NULL;
1037 	uint32_t object_handle = 0;
1038 	uint32_t obj_handle = 0;
1039 	enum processing_func function = PKCS11_FUNCTION_COPY;
1040 	enum pkcs11_class_id class = PKCS11_CKO_UNDEFINED_ID;
1041 
1042 	if (!client || ptypes != exp_pt ||
1043 	    out->memref.size != sizeof(obj_handle))
1044 		return PKCS11_CKR_ARGUMENTS_BAD;
1045 
1046 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
1047 
1048 	rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
1049 	if (rc)
1050 		return rc;
1051 
1052 	rc = serialargs_get(&ctrlargs, &object_handle, sizeof(uint32_t));
1053 	if (rc)
1054 		return rc;
1055 
1056 	rc = serialargs_alloc_get_attributes(&ctrlargs, &template);
1057 	if (rc)
1058 		return rc;
1059 
1060 	if (serialargs_remaining_bytes(&ctrlargs)) {
1061 		rc = PKCS11_CKR_ARGUMENTS_BAD;
1062 		goto out;
1063 	}
1064 
1065 	obj = pkcs11_handle2object(object_handle, session);
1066 	if (!obj) {
1067 		rc = PKCS11_CKR_OBJECT_HANDLE_INVALID;
1068 		goto out;
1069 	}
1070 
1071 	/* Only session objects can be modified during a read-only session */
1072 	if (object_is_token(obj->attributes) &&
1073 	    !pkcs11_session_is_read_write(session)) {
1074 		DMSG("Can't modify persistent object in a RO session");
1075 		rc = PKCS11_CKR_SESSION_READ_ONLY;
1076 		goto out;
1077 	}
1078 
1079 	/*
1080 	 * Only public objects can be modified unless normal user is logged in
1081 	 */
1082 	rc = check_access_attrs_against_token(session, obj->attributes);
1083 	if (rc) {
1084 		rc = PKCS11_CKR_USER_NOT_LOGGED_IN;
1085 		goto out;
1086 	}
1087 
1088 	/* Objects with PKCS11_CKA_COPYABLE as false can't be copied */
1089 	if (!object_is_copyable(obj->attributes)) {
1090 		rc = PKCS11_CKR_ACTION_PROHIBITED;
1091 		goto out;
1092 	}
1093 
1094 	template_size = sizeof(*template) + template->attrs_size;
1095 
1096 	/*
1097 	 * Prepare a clean initial state (@head) for the template. Helps in
1098 	 * removing any duplicates or inconsistent values from the
1099 	 * template.
1100 	 */
1101 	rc = create_attributes_from_template(&head, template, template_size,
1102 					     NULL, function,
1103 					     PKCS11_CKM_UNDEFINED_ID,
1104 					     PKCS11_CKO_UNDEFINED_ID);
1105 	if (rc)
1106 		goto out;
1107 
1108 	/* Check the attributes in @head to see if they are modifiable */
1109 	rc = check_attrs_against_modification(session, head, obj, function);
1110 	if (rc)
1111 		goto out;
1112 
1113 	class = get_class(obj->attributes);
1114 
1115 	if (class == PKCS11_CKO_SECRET_KEY ||
1116 	    class == PKCS11_CKO_PRIVATE_KEY) {
1117 		/*
1118 		 * If CKA_EXTRACTABLE attribute in passed template (@head) is
1119 		 * modified to CKA_FALSE, CKA_NEVER_EXTRACTABLE should also
1120 		 * change to CKA_FALSE in copied obj. So, add it to the
1121 		 * passed template.
1122 		 */
1123 		uint8_t bbool = 0;
1124 		uint32_t size = sizeof(bbool);
1125 
1126 		rc = get_attribute(head, PKCS11_CKA_EXTRACTABLE, &bbool, &size);
1127 		if (!rc && !bbool) {
1128 			rc = add_attribute(&head, PKCS11_CKA_NEVER_EXTRACTABLE,
1129 					   &bbool, sizeof(uint8_t));
1130 			if (rc)
1131 				goto out;
1132 		}
1133 		rc = PKCS11_CKR_OK;
1134 	}
1135 
1136 	/*
1137 	 * All checks have passed. Create a copy of the serialized buffer which
1138 	 * holds the object attributes in @head_new for the new object
1139 	 */
1140 	template_size = sizeof(*obj->attributes) + obj->attributes->attrs_size;
1141 	head_new = TEE_Malloc(template_size, TEE_MALLOC_FILL_ZERO);
1142 	if (!head_new) {
1143 		rc = PKCS11_CKR_DEVICE_MEMORY;
1144 		goto out;
1145 	}
1146 
1147 	TEE_MemMove(head_new, obj->attributes, template_size);
1148 
1149 	/*
1150 	 * Modify the copied attribute @head_new based on the template @head
1151 	 * given by the callee
1152 	 */
1153 	rc = modify_attributes_list(&head_new, head);
1154 	if (rc)
1155 		goto out;
1156 
1157 	/*
1158 	 * At this stage the object is almost created: all its attributes are
1159 	 * referenced in @head_new, including the key value and are assumed
1160 	 * reliable. Now need to register it and get a handle for it.
1161 	 */
1162 	rc = create_object(session, head_new, &obj_handle);
1163 	if (rc)
1164 		goto out;
1165 
1166 	/*
1167 	 * Now obj_handle (through the related struct pkcs11_object
1168 	 * instance) owns the serialized buffer that holds the object
1169 	 * attributes. We clear reference in head to NULL as the serializer
1170 	 * object is now referred from obj_handle. This allows smooth pass
1171 	 * through free at function exit.
1172 	 */
1173 	head_new = NULL;
1174 
1175 	TEE_MemMove(out->memref.buffer, &obj_handle, sizeof(obj_handle));
1176 	out->memref.size = sizeof(obj_handle);
1177 
1178 	DMSG("PKCS11 session %"PRIu32": copy object %#"PRIx32,
1179 	     session->handle, obj_handle);
1180 
1181 out:
1182 	TEE_Free(head_new);
1183 	TEE_Free(head);
1184 	TEE_Free(template);
1185 	return rc;
1186 }
1187