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