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