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