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