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