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 void release_find_obj_context(struct pkcs11_find_objects *find_ctx) 432 { 433 if (!find_ctx) 434 return; 435 436 TEE_Free(find_ctx->attributes); 437 TEE_Free(find_ctx->handles); 438 TEE_Free(find_ctx); 439 } 440 441 static enum pkcs11_rc find_ctx_add(struct pkcs11_find_objects *find_ctx, 442 uint32_t handle) 443 { 444 uint32_t *hdls = TEE_Realloc(find_ctx->handles, 445 (find_ctx->count + 1) * sizeof(*hdls)); 446 447 if (!hdls) 448 return PKCS11_CKR_DEVICE_MEMORY; 449 450 find_ctx->handles = hdls; 451 452 *(find_ctx->handles + find_ctx->count) = handle; 453 find_ctx->count++; 454 455 return PKCS11_CKR_OK; 456 } 457 458 enum pkcs11_rc entry_find_objects_init(struct pkcs11_client *client, 459 uint32_t ptypes, TEE_Param *params) 460 { 461 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 462 TEE_PARAM_TYPE_NONE, 463 TEE_PARAM_TYPE_NONE, 464 TEE_PARAM_TYPE_NONE); 465 TEE_Param *ctrl = params; 466 enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR; 467 struct serialargs ctrlargs = { }; 468 struct pkcs11_session *session = NULL; 469 struct pkcs11_object_head *template = NULL; 470 struct obj_attrs *req_attrs = NULL; 471 struct pkcs11_object *obj = NULL; 472 struct pkcs11_find_objects *find_ctx = NULL; 473 474 if (!client || ptypes != exp_pt) 475 return PKCS11_CKR_ARGUMENTS_BAD; 476 477 serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 478 479 rc = serialargs_get_session_from_handle(&ctrlargs, client, &session); 480 if (rc) 481 return rc; 482 483 rc = serialargs_alloc_get_attributes(&ctrlargs, &template); 484 if (rc) 485 return rc; 486 487 if (serialargs_remaining_bytes(&ctrlargs)) { 488 rc = PKCS11_CKR_ARGUMENTS_BAD; 489 goto out; 490 } 491 492 /* Search objects only if no operation is on-going */ 493 if (session_is_active(session)) { 494 rc = PKCS11_CKR_OPERATION_ACTIVE; 495 goto out; 496 } 497 498 if (session->find_ctx) { 499 EMSG("Active object search already in progress"); 500 rc = PKCS11_CKR_FUNCTION_FAILED; 501 goto out; 502 } 503 504 rc = sanitize_client_object(&req_attrs, template, 505 sizeof(*template) + template->attrs_size, 506 PKCS11_UNDEFINED_ID, PKCS11_UNDEFINED_ID); 507 if (rc) 508 goto out; 509 510 /* Must zero init the structure */ 511 find_ctx = TEE_Malloc(sizeof(*find_ctx), TEE_MALLOC_FILL_ZERO); 512 if (!find_ctx) { 513 rc = PKCS11_CKR_DEVICE_MEMORY; 514 goto out; 515 } 516 517 TEE_Free(template); 518 template = NULL; 519 520 switch (get_class(req_attrs)) { 521 case PKCS11_CKO_UNDEFINED_ID: 522 /* Unspecified class searches among data objects */ 523 case PKCS11_CKO_SECRET_KEY: 524 case PKCS11_CKO_PUBLIC_KEY: 525 case PKCS11_CKO_PRIVATE_KEY: 526 case PKCS11_CKO_DATA: 527 break; 528 default: 529 EMSG("Find object of class %s (%"PRIu32") is not supported", 530 id2str_class(get_class(req_attrs)), 531 get_class(req_attrs)); 532 rc = PKCS11_CKR_ARGUMENTS_BAD; 533 goto out; 534 } 535 536 /* 537 * Scan all objects (sessions and persistent ones) and set a list of 538 * candidates that match caller attributes. 539 */ 540 541 LIST_FOREACH(obj, &session->object_list, link) { 542 if (check_access_attrs_against_token(session, obj->attributes)) 543 continue; 544 545 if (!attributes_match_reference(obj->attributes, req_attrs)) 546 continue; 547 548 rc = find_ctx_add(find_ctx, pkcs11_object2handle(obj, session)); 549 if (rc) 550 goto out; 551 } 552 553 LIST_FOREACH(obj, &session->token->object_list, link) { 554 uint32_t handle = 0; 555 bool new_load = false; 556 557 if (!obj->attributes) { 558 rc = load_persistent_object_attributes(obj); 559 if (rc) 560 return PKCS11_CKR_GENERAL_ERROR; 561 562 new_load = true; 563 } 564 565 if (!obj->attributes || 566 check_access_attrs_against_token(session, 567 obj->attributes) || 568 !attributes_match_reference(obj->attributes, req_attrs)) { 569 if (new_load) 570 release_persistent_object_attributes(obj); 571 572 continue; 573 } 574 575 /* Object may not yet be published in the session */ 576 handle = pkcs11_object2handle(obj, session); 577 if (!handle) { 578 handle = handle_get(&session->object_handle_db, obj); 579 if (!handle) { 580 rc = PKCS11_CKR_DEVICE_MEMORY; 581 goto out; 582 } 583 } 584 585 rc = find_ctx_add(find_ctx, handle); 586 if (rc) 587 goto out; 588 } 589 590 find_ctx->attributes = req_attrs; 591 req_attrs = NULL; 592 session->find_ctx = find_ctx; 593 find_ctx = NULL; 594 rc = PKCS11_CKR_OK; 595 596 out: 597 TEE_Free(req_attrs); 598 TEE_Free(template); 599 release_find_obj_context(find_ctx); 600 601 return rc; 602 } 603 604 enum pkcs11_rc entry_find_objects(struct pkcs11_client *client, 605 uint32_t ptypes, TEE_Param *params) 606 { 607 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 608 TEE_PARAM_TYPE_NONE, 609 TEE_PARAM_TYPE_MEMREF_OUTPUT, 610 TEE_PARAM_TYPE_NONE); 611 TEE_Param *ctrl = params; 612 TEE_Param *out = params + 2; 613 enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR; 614 struct serialargs ctrlargs = { }; 615 struct pkcs11_session *session = NULL; 616 struct pkcs11_find_objects *ctx = NULL; 617 uint8_t *out_handles = NULL; 618 size_t out_count = 0; 619 size_t count = 0; 620 621 if (!client || ptypes != exp_pt) 622 return PKCS11_CKR_ARGUMENTS_BAD; 623 624 out_count = out->memref.size / sizeof(uint32_t); 625 out_handles = out->memref.buffer; 626 627 serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 628 629 rc = serialargs_get_session_from_handle(&ctrlargs, client, &session); 630 if (rc) 631 return rc; 632 633 if (serialargs_remaining_bytes(&ctrlargs)) 634 return PKCS11_CKR_ARGUMENTS_BAD; 635 636 ctx = session->find_ctx; 637 638 if (!ctx) 639 return PKCS11_CKR_OPERATION_NOT_INITIALIZED; 640 641 for (count = 0; ctx->next < ctx->count && count < out_count; 642 ctx->next++, count++) 643 TEE_MemMove(out_handles + count * sizeof(uint32_t), 644 ctx->handles + ctx->next, sizeof(uint32_t)); 645 646 /* Update output buffer according the number of handles provided */ 647 out->memref.size = count * sizeof(uint32_t); 648 649 DMSG("PKCS11 session %"PRIu32": finding objects", session->handle); 650 651 return PKCS11_CKR_OK; 652 } 653 654 void release_session_find_obj_context(struct pkcs11_session *session) 655 { 656 release_find_obj_context(session->find_ctx); 657 session->find_ctx = NULL; 658 } 659 660 uint32_t entry_find_objects_final(struct pkcs11_client *client, 661 uint32_t ptypes, TEE_Param *params) 662 { 663 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 664 TEE_PARAM_TYPE_NONE, 665 TEE_PARAM_TYPE_NONE, 666 TEE_PARAM_TYPE_NONE); 667 TEE_Param *ctrl = params; 668 enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR; 669 struct serialargs ctrlargs = { }; 670 struct pkcs11_session *session = NULL; 671 672 if (!client || ptypes != exp_pt) 673 return PKCS11_CKR_ARGUMENTS_BAD; 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 if (!session->find_ctx) 685 return PKCS11_CKR_OPERATION_NOT_INITIALIZED; 686 687 release_session_find_obj_context(session); 688 689 return PKCS11_CKR_OK; 690 } 691 692 uint32_t entry_get_attribute_value(struct pkcs11_client *client, 693 uint32_t ptypes, TEE_Param *params) 694 { 695 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 696 TEE_PARAM_TYPE_NONE, 697 TEE_PARAM_TYPE_MEMREF_OUTPUT, 698 TEE_PARAM_TYPE_NONE); 699 TEE_Param *ctrl = params; 700 TEE_Param *out = params + 2; 701 enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR; 702 struct serialargs ctrlargs = { }; 703 struct pkcs11_session *session = NULL; 704 struct pkcs11_object_head *template = NULL; 705 struct pkcs11_object *obj = NULL; 706 uint32_t object_handle = 0; 707 char *cur = NULL; 708 size_t len = 0; 709 char *end = NULL; 710 bool attr_sensitive = 0; 711 bool attr_type_invalid = 0; 712 bool buffer_too_small = 0; 713 714 if (!client || ptypes != exp_pt) 715 return PKCS11_CKR_ARGUMENTS_BAD; 716 717 serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 718 719 rc = serialargs_get_session_from_handle(&ctrlargs, client, &session); 720 if (rc) 721 return rc; 722 723 rc = serialargs_get(&ctrlargs, &object_handle, sizeof(uint32_t)); 724 if (rc) 725 return rc; 726 727 rc = serialargs_alloc_get_attributes(&ctrlargs, &template); 728 if (rc) 729 return rc; 730 731 if (serialargs_remaining_bytes(&ctrlargs)) { 732 rc = PKCS11_CKR_ARGUMENTS_BAD; 733 goto out; 734 } 735 736 obj = pkcs11_handle2object(object_handle, session); 737 if (!obj) { 738 rc = PKCS11_CKR_OBJECT_HANDLE_INVALID; 739 goto out; 740 } 741 742 rc = check_access_attrs_against_token(session, obj->attributes); 743 if (rc) { 744 rc = PKCS11_CKR_OBJECT_HANDLE_INVALID; 745 goto out; 746 } 747 748 /* Iterate over attributes and set their values */ 749 /* 750 * 1. If the specified attribute (i.e., the attribute specified by the 751 * type field) for the object cannot be revealed because the object is 752 * sensitive or unextractable, then the ulValueLen field in that triple 753 * is modified to hold the value PKCS11_CK_UNAVAILABLE_INFORMATION. 754 * 755 * 2. Otherwise, if the specified value for the object is invalid (the 756 * object does not possess such an attribute), then the ulValueLen field 757 * in that triple is modified to hold the value 758 * PKCS11_CK_UNAVAILABLE_INFORMATION. 759 * 760 * 3. Otherwise, if the pValue field has the value NULL_PTR, then the 761 * ulValueLen field is modified to hold the exact length of the 762 * specified attribute for the object. 763 * 764 * 4. Otherwise, if the length specified in ulValueLen is large enough 765 * to hold the value of the specified attribute for the object, then 766 * that attribute is copied into the buffer located at pValue, and the 767 * ulValueLen field is modified to hold the exact length of the 768 * attribute. 769 * 770 * 5. Otherwise, the ulValueLen field is modified to hold the value 771 * PKCS11_CK_UNAVAILABLE_INFORMATION. 772 */ 773 cur = (char *)template + sizeof(struct pkcs11_object_head); 774 end = cur + template->attrs_size; 775 776 for (; cur < end; cur += len) { 777 struct pkcs11_attribute_head *cli_ref = (void *)cur; 778 struct pkcs11_attribute_head cli_head = { }; 779 void *data_ptr = NULL; 780 781 /* Make copy of header so that is aligned properly. */ 782 TEE_MemMove(&cli_head, cli_ref, sizeof(cli_head)); 783 784 len = sizeof(*cli_ref) + cli_head.size; 785 786 /* Check 1. */ 787 if (!attribute_is_exportable(&cli_head, obj)) { 788 cli_head.size = PKCS11_CK_UNAVAILABLE_INFORMATION; 789 TEE_MemMove(&cli_ref->size, &cli_head.size, 790 sizeof(cli_head.size)); 791 attr_sensitive = 1; 792 continue; 793 } 794 795 /* Get real data pointer from template data */ 796 data_ptr = cli_head.size ? cli_ref->data : NULL; 797 798 /* 799 * We assume that if size is 0, pValue was NULL, so we return 800 * the size of the required buffer for it (3., 4.) 801 */ 802 rc = get_attribute(obj->attributes, cli_head.id, data_ptr, 803 &cli_head.size); 804 /* Check 2. */ 805 switch (rc) { 806 case PKCS11_CKR_OK: 807 break; 808 case PKCS11_RV_NOT_FOUND: 809 cli_head.size = PKCS11_CK_UNAVAILABLE_INFORMATION; 810 attr_type_invalid = 1; 811 break; 812 case PKCS11_CKR_BUFFER_TOO_SMALL: 813 if (data_ptr) 814 buffer_too_small = 1; 815 break; 816 default: 817 rc = PKCS11_CKR_GENERAL_ERROR; 818 goto out; 819 } 820 821 TEE_MemMove(&cli_ref->size, &cli_head.size, 822 sizeof(cli_head.size)); 823 } 824 825 /* 826 * If case 1 applies to any of the requested attributes, then the call 827 * should return the value CKR_ATTRIBUTE_SENSITIVE. If case 2 applies to 828 * any of the requested attributes, then the call should return the 829 * value CKR_ATTRIBUTE_TYPE_INVALID. If case 5 applies to any of the 830 * requested attributes, then the call should return the value 831 * CKR_BUFFER_TOO_SMALL. As usual, if more than one of these error codes 832 * is applicable, Cryptoki may return any of them. Only if none of them 833 * applies to any of the requested attributes will CKR_OK be returned. 834 */ 835 836 rc = PKCS11_CKR_OK; 837 if (attr_sensitive) 838 rc = PKCS11_CKR_ATTRIBUTE_SENSITIVE; 839 if (attr_type_invalid) 840 rc = PKCS11_CKR_ATTRIBUTE_TYPE_INVALID; 841 if (buffer_too_small) 842 rc = PKCS11_CKR_BUFFER_TOO_SMALL; 843 844 /* Move updated template to out buffer */ 845 TEE_MemMove(out->memref.buffer, template, out->memref.size); 846 847 DMSG("PKCS11 session %"PRIu32": get attributes %#"PRIx32, 848 session->handle, object_handle); 849 850 out: 851 TEE_Free(template); 852 853 return rc; 854 } 855 856 uint32_t entry_get_object_size(struct pkcs11_client *client, 857 uint32_t ptypes, TEE_Param *params) 858 { 859 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 860 TEE_PARAM_TYPE_NONE, 861 TEE_PARAM_TYPE_MEMREF_OUTPUT, 862 TEE_PARAM_TYPE_NONE); 863 TEE_Param *ctrl = params; 864 TEE_Param *out = params + 2; 865 enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR; 866 struct serialargs ctrlargs = { }; 867 struct pkcs11_session *session = NULL; 868 uint32_t object_handle = 0; 869 struct pkcs11_object *obj = NULL; 870 uint32_t obj_size = 0; 871 872 if (!client || ptypes != exp_pt) 873 return PKCS11_CKR_ARGUMENTS_BAD; 874 875 serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 876 877 rc = serialargs_get_session_from_handle(&ctrlargs, client, &session); 878 if (rc) 879 return rc; 880 881 rc = serialargs_get(&ctrlargs, &object_handle, sizeof(uint32_t)); 882 if (rc) 883 return rc; 884 885 if (serialargs_remaining_bytes(&ctrlargs)) 886 return PKCS11_CKR_ARGUMENTS_BAD; 887 888 obj = pkcs11_handle2object(object_handle, session); 889 if (!obj) 890 return PKCS11_CKR_OBJECT_HANDLE_INVALID; 891 892 rc = check_access_attrs_against_token(session, obj->attributes); 893 if (rc) 894 return PKCS11_CKR_OBJECT_HANDLE_INVALID; 895 896 if (out->memref.size != sizeof(uint32_t)) 897 return PKCS11_CKR_ARGUMENTS_BAD; 898 899 obj_size = ((struct obj_attrs *)obj->attributes)->attrs_size + 900 sizeof(struct obj_attrs); 901 TEE_MemMove(out->memref.buffer, &obj_size, sizeof(obj_size)); 902 903 return PKCS11_CKR_OK; 904 } 905