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