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 /* 804 * We will update the template with relevant data, without resizing it. 805 * Upon completion, it will be copied to client output buffer. 806 */ 807 if (out->memref.size < sizeof(*template) + template->attrs_size) { 808 rc = PKCS11_CKR_ARGUMENTS_BAD; 809 goto out; 810 } 811 812 /* Iterate over attributes and set their values */ 813 /* 814 * 1. If the specified attribute (i.e., the attribute specified by the 815 * type field) for the object cannot be revealed because the object is 816 * sensitive or unextractable, then the ulValueLen field in that triple 817 * is modified to hold the value PKCS11_CK_UNAVAILABLE_INFORMATION. 818 * 819 * 2. Otherwise, if the specified value for the object is invalid (the 820 * object does not possess such an attribute), then the ulValueLen field 821 * in that triple is modified to hold the value 822 * PKCS11_CK_UNAVAILABLE_INFORMATION. 823 * 824 * 3. Otherwise, if the pValue field has the value NULL_PTR, then the 825 * ulValueLen field is modified to hold the exact length of the 826 * specified attribute for the object. 827 * 828 * 4. Otherwise, if the length specified in ulValueLen is large enough 829 * to hold the value of the specified attribute for the object, then 830 * that attribute is copied into the buffer located at pValue, and the 831 * ulValueLen field is modified to hold the exact length of the 832 * attribute. 833 * 834 * 5. Otherwise, the ulValueLen field is modified to hold the value 835 * PKCS11_CK_UNAVAILABLE_INFORMATION. 836 */ 837 cur = (char *)template + sizeof(struct pkcs11_object_head); 838 end = cur + template->attrs_size; 839 840 for (; cur < end; cur += len) { 841 struct pkcs11_attribute_head *cli_ref = (void *)cur; 842 struct pkcs11_attribute_head cli_head = { }; 843 uintptr_t cli_end = 0; 844 void *data_ptr = NULL; 845 846 if ((char *)(cli_ref + 1) > end) { 847 rc = PKCS11_CKR_ARGUMENTS_BAD; 848 goto out; 849 } 850 851 /* Make copy of header so that is aligned properly. */ 852 TEE_MemMove(&cli_head, cli_ref, sizeof(cli_head)); 853 854 if (ADD_OVERFLOW(sizeof(*cli_ref), cli_head.size, &len) || 855 ADD_OVERFLOW((uintptr_t)cur, len, &cli_end) || 856 (char *)cli_end > end) { 857 rc = PKCS11_CKR_ARGUMENTS_BAD; 858 goto out; 859 } 860 861 /* Treat hidden attributes as missing attributes */ 862 if (attribute_is_hidden(&cli_head)) { 863 cli_head.size = PKCS11_CK_UNAVAILABLE_INFORMATION; 864 TEE_MemMove(&cli_ref->size, &cli_head.size, 865 sizeof(cli_head.size)); 866 attr_type_invalid = 1; 867 continue; 868 } 869 870 /* We don't support getting value of indirect templates */ 871 if (pkcs11_attr_has_indirect_attributes(cli_head.id)) { 872 attr_type_invalid = 1; 873 continue; 874 } 875 876 /* Check 1. */ 877 if (!attribute_is_exportable(&cli_head, obj)) { 878 cli_head.size = PKCS11_CK_UNAVAILABLE_INFORMATION; 879 TEE_MemMove(&cli_ref->size, &cli_head.size, 880 sizeof(cli_head.size)); 881 attr_sensitive = 1; 882 continue; 883 } 884 885 /* Get real data pointer from template data */ 886 data_ptr = cli_head.size ? cli_ref->data : NULL; 887 888 /* 889 * We assume that if size is 0, pValue was NULL, so we return 890 * the size of the required buffer for it (3., 4.) 891 */ 892 rc = get_attribute(obj->attributes, cli_head.id, data_ptr, 893 &cli_head.size); 894 /* Check 2. */ 895 switch (rc) { 896 case PKCS11_CKR_OK: 897 break; 898 case PKCS11_RV_NOT_FOUND: 899 cli_head.size = PKCS11_CK_UNAVAILABLE_INFORMATION; 900 attr_type_invalid = 1; 901 break; 902 case PKCS11_CKR_BUFFER_TOO_SMALL: 903 if (data_ptr) { 904 cli_head.size = 905 PKCS11_CK_UNAVAILABLE_INFORMATION; 906 buffer_too_small = 1; 907 } 908 break; 909 default: 910 rc = PKCS11_CKR_GENERAL_ERROR; 911 goto out; 912 } 913 914 TEE_MemMove(&cli_ref->size, &cli_head.size, 915 sizeof(cli_head.size)); 916 } 917 918 /* 919 * If case 1 applies to any of the requested attributes, then the call 920 * should return the value CKR_ATTRIBUTE_SENSITIVE. If case 2 applies to 921 * any of the requested attributes, then the call should return the 922 * value CKR_ATTRIBUTE_TYPE_INVALID. If case 5 applies to any of the 923 * requested attributes, then the call should return the value 924 * CKR_BUFFER_TOO_SMALL. As usual, if more than one of these error codes 925 * is applicable, Cryptoki may return any of them. Only if none of them 926 * applies to any of the requested attributes will CKR_OK be returned. 927 */ 928 929 rc = PKCS11_CKR_OK; 930 if (attr_sensitive) 931 rc = PKCS11_CKR_ATTRIBUTE_SENSITIVE; 932 if (attr_type_invalid) 933 rc = PKCS11_CKR_ATTRIBUTE_TYPE_INVALID; 934 if (buffer_too_small) 935 rc = PKCS11_CKR_BUFFER_TOO_SMALL; 936 937 /* Move updated template to out buffer */ 938 out->memref.size = sizeof(*template) + template->attrs_size; 939 TEE_MemMove(out->memref.buffer, template, out->memref.size); 940 941 DMSG("PKCS11 session %"PRIu32": get attributes %#"PRIx32, 942 session->handle, object_handle); 943 944 out: 945 TEE_Free(template); 946 947 return rc; 948 } 949 950 enum pkcs11_rc entry_get_object_size(struct pkcs11_client *client, 951 uint32_t ptypes, TEE_Param *params) 952 { 953 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 954 TEE_PARAM_TYPE_NONE, 955 TEE_PARAM_TYPE_MEMREF_OUTPUT, 956 TEE_PARAM_TYPE_NONE); 957 TEE_Param *ctrl = params; 958 TEE_Param *out = params + 2; 959 enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR; 960 struct serialargs ctrlargs = { }; 961 struct pkcs11_session *session = NULL; 962 uint32_t object_handle = 0; 963 struct pkcs11_object *obj = NULL; 964 uint32_t obj_size = 0; 965 966 if (!client || ptypes != exp_pt) 967 return PKCS11_CKR_ARGUMENTS_BAD; 968 969 serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 970 971 rc = serialargs_get_session_from_handle(&ctrlargs, client, &session); 972 if (rc) 973 return rc; 974 975 rc = serialargs_get(&ctrlargs, &object_handle, sizeof(uint32_t)); 976 if (rc) 977 return rc; 978 979 if (serialargs_remaining_bytes(&ctrlargs)) 980 return PKCS11_CKR_ARGUMENTS_BAD; 981 982 obj = pkcs11_handle2object(object_handle, session); 983 if (!obj) 984 return PKCS11_CKR_OBJECT_HANDLE_INVALID; 985 986 rc = check_access_attrs_against_token(session, obj->attributes); 987 if (rc) 988 return PKCS11_CKR_OBJECT_HANDLE_INVALID; 989 990 if (out->memref.size != sizeof(uint32_t)) 991 return PKCS11_CKR_ARGUMENTS_BAD; 992 993 obj_size = ((struct obj_attrs *)obj->attributes)->attrs_size + 994 sizeof(struct obj_attrs); 995 TEE_MemMove(out->memref.buffer, &obj_size, sizeof(obj_size)); 996 997 return PKCS11_CKR_OK; 998 } 999 1000 enum pkcs11_rc entry_set_attribute_value(struct pkcs11_client *client, 1001 uint32_t ptypes, TEE_Param *params) 1002 { 1003 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 1004 TEE_PARAM_TYPE_NONE, 1005 TEE_PARAM_TYPE_NONE, 1006 TEE_PARAM_TYPE_NONE); 1007 TEE_Param *ctrl = params; 1008 enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR; 1009 struct serialargs ctrlargs = { }; 1010 struct pkcs11_session *session = NULL; 1011 struct pkcs11_object_head *template = NULL; 1012 size_t template_size = 0; 1013 struct pkcs11_object *obj = NULL; 1014 struct obj_attrs *head = NULL; 1015 struct obj_attrs *head_new = NULL; 1016 struct obj_attrs *head_old = NULL; 1017 uint32_t object_handle = 0; 1018 enum processing_func function = PKCS11_FUNCTION_MODIFY; 1019 1020 if (!client || ptypes != exp_pt) 1021 return PKCS11_CKR_ARGUMENTS_BAD; 1022 1023 serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 1024 1025 rc = serialargs_get_session_from_handle(&ctrlargs, client, &session); 1026 if (rc) 1027 return rc; 1028 1029 rc = serialargs_get(&ctrlargs, &object_handle, sizeof(uint32_t)); 1030 if (rc) 1031 return rc; 1032 1033 rc = serialargs_alloc_get_attributes(&ctrlargs, &template); 1034 if (rc) 1035 return rc; 1036 1037 if (serialargs_remaining_bytes(&ctrlargs)) { 1038 rc = PKCS11_CKR_ARGUMENTS_BAD; 1039 goto out; 1040 } 1041 1042 obj = pkcs11_handle2object(object_handle, session); 1043 if (!obj) { 1044 rc = PKCS11_CKR_OBJECT_HANDLE_INVALID; 1045 goto out; 1046 } 1047 1048 /* Only session objects can be modified during a read-only session */ 1049 if (object_is_token(obj->attributes) && 1050 !pkcs11_session_is_read_write(session)) { 1051 DMSG("Can't modify persistent object in a RO session"); 1052 rc = PKCS11_CKR_SESSION_READ_ONLY; 1053 goto out; 1054 } 1055 1056 /* 1057 * Only public objects can be modified unless normal user is logged in 1058 */ 1059 rc = check_access_attrs_against_token(session, obj->attributes); 1060 if (rc) { 1061 rc = PKCS11_CKR_USER_NOT_LOGGED_IN; 1062 goto out; 1063 } 1064 1065 /* Objects with PKCS11_CKA_MODIFIABLE as false aren't modifiable */ 1066 if (!object_is_modifiable(obj->attributes)) { 1067 rc = PKCS11_CKR_ACTION_PROHIBITED; 1068 goto out; 1069 } 1070 1071 template_size = sizeof(*template) + template->attrs_size; 1072 1073 /* 1074 * Prepare a clean initial state (@head) for the template. Helps in 1075 * removing any duplicates or inconsistent values from the 1076 * template. 1077 */ 1078 rc = create_attributes_from_template(&head, template, template_size, 1079 NULL, function, 1080 PKCS11_CKM_UNDEFINED_ID, 1081 PKCS11_CKO_UNDEFINED_ID); 1082 if (rc) 1083 goto out; 1084 1085 /* Check the attributes in @head to see if they are modifiable */ 1086 rc = check_attrs_against_modification(session, head, obj, function); 1087 if (rc) 1088 goto out; 1089 1090 /* Create new object attributes to modify */ 1091 template_size = sizeof(*obj->attributes) + obj->attributes->attrs_size; 1092 head_new = TEE_Malloc(template_size, TEE_MALLOC_FILL_ZERO); 1093 if (!head_new) { 1094 rc = PKCS11_CKR_DEVICE_MEMORY; 1095 goto out; 1096 } 1097 1098 TEE_MemMove(head_new, obj->attributes, template_size); 1099 1100 /* 1101 * All checks complete. The attributes in @head have been checked and 1102 * can now be used to set/modify the object attributes. 1103 */ 1104 rc = modify_attributes_list(&head_new, head); 1105 if (rc) 1106 goto out; 1107 1108 /* Set key check value attribute */ 1109 rc = set_check_value_attr(&head_new); 1110 if (rc) 1111 goto out; 1112 1113 /* Update the object */ 1114 head_old = obj->attributes; 1115 obj->attributes = head_new; 1116 head_new = NULL; 1117 1118 if (get_bool(obj->attributes, PKCS11_CKA_TOKEN)) { 1119 rc = update_persistent_object_attributes(obj); 1120 if (rc) { 1121 TEE_Free(obj->attributes); 1122 obj->attributes = head_old; 1123 goto out; 1124 } 1125 } 1126 1127 TEE_Free(head_old); 1128 1129 DMSG("PKCS11 session %"PRIu32": set attributes %#"PRIx32, 1130 session->handle, object_handle); 1131 1132 out: 1133 TEE_Free(head); 1134 TEE_Free(head_new); 1135 TEE_Free(template); 1136 return rc; 1137 } 1138 1139 enum pkcs11_rc entry_copy_object(struct pkcs11_client *client, uint32_t ptypes, 1140 TEE_Param *params) 1141 { 1142 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 1143 TEE_PARAM_TYPE_NONE, 1144 TEE_PARAM_TYPE_MEMREF_OUTPUT, 1145 TEE_PARAM_TYPE_NONE); 1146 TEE_Param *ctrl = params; 1147 TEE_Param *out = params + 2; 1148 enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR; 1149 struct serialargs ctrlargs = { }; 1150 struct pkcs11_session *session = NULL; 1151 struct pkcs11_object_head *template = NULL; 1152 struct obj_attrs *head = NULL; 1153 struct obj_attrs *head_new = NULL; 1154 size_t template_size = 0; 1155 struct pkcs11_object *obj = NULL; 1156 uint32_t object_handle = 0; 1157 uint32_t obj_handle = 0; 1158 enum processing_func function = PKCS11_FUNCTION_COPY; 1159 enum pkcs11_class_id class = PKCS11_CKO_UNDEFINED_ID; 1160 1161 if (!client || ptypes != exp_pt || 1162 out->memref.size != sizeof(obj_handle)) 1163 return PKCS11_CKR_ARGUMENTS_BAD; 1164 1165 serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 1166 1167 rc = serialargs_get_session_from_handle(&ctrlargs, client, &session); 1168 if (rc) 1169 return rc; 1170 1171 rc = serialargs_get(&ctrlargs, &object_handle, sizeof(uint32_t)); 1172 if (rc) 1173 return rc; 1174 1175 rc = serialargs_alloc_get_attributes(&ctrlargs, &template); 1176 if (rc) 1177 return rc; 1178 1179 if (serialargs_remaining_bytes(&ctrlargs)) { 1180 rc = PKCS11_CKR_ARGUMENTS_BAD; 1181 goto out; 1182 } 1183 1184 obj = pkcs11_handle2object(object_handle, session); 1185 if (!obj) { 1186 rc = PKCS11_CKR_OBJECT_HANDLE_INVALID; 1187 goto out; 1188 } 1189 1190 /* Only session objects can be modified during a read-only session */ 1191 if (object_is_token(obj->attributes) && 1192 !pkcs11_session_is_read_write(session)) { 1193 DMSG("Can't modify persistent object in a RO session"); 1194 rc = PKCS11_CKR_SESSION_READ_ONLY; 1195 goto out; 1196 } 1197 1198 /* 1199 * Only public objects can be modified unless normal user is logged in 1200 */ 1201 rc = check_access_attrs_against_token(session, obj->attributes); 1202 if (rc) { 1203 rc = PKCS11_CKR_USER_NOT_LOGGED_IN; 1204 goto out; 1205 } 1206 1207 /* Objects with PKCS11_CKA_COPYABLE as false can't be copied */ 1208 if (!object_is_copyable(obj->attributes)) { 1209 rc = PKCS11_CKR_ACTION_PROHIBITED; 1210 goto out; 1211 } 1212 1213 template_size = sizeof(*template) + template->attrs_size; 1214 1215 /* 1216 * Prepare a clean initial state (@head) for the template. Helps in 1217 * removing any duplicates or inconsistent values from the 1218 * template. 1219 */ 1220 rc = create_attributes_from_template(&head, template, template_size, 1221 NULL, function, 1222 PKCS11_CKM_UNDEFINED_ID, 1223 PKCS11_CKO_UNDEFINED_ID); 1224 if (rc) 1225 goto out; 1226 1227 /* Check the attributes in @head to see if they are modifiable */ 1228 rc = check_attrs_against_modification(session, head, obj, function); 1229 if (rc) 1230 goto out; 1231 1232 class = get_class(obj->attributes); 1233 1234 if (class == PKCS11_CKO_SECRET_KEY || 1235 class == PKCS11_CKO_PRIVATE_KEY) { 1236 /* 1237 * If CKA_EXTRACTABLE attribute in passed template (@head) is 1238 * modified to CKA_FALSE, CKA_NEVER_EXTRACTABLE should also 1239 * change to CKA_FALSE in copied obj. So, add it to the 1240 * passed template. 1241 */ 1242 uint8_t bbool = 0; 1243 uint32_t size = sizeof(bbool); 1244 1245 rc = get_attribute(head, PKCS11_CKA_EXTRACTABLE, &bbool, &size); 1246 if (!rc && !bbool) { 1247 rc = add_attribute(&head, PKCS11_CKA_NEVER_EXTRACTABLE, 1248 &bbool, sizeof(uint8_t)); 1249 if (rc) 1250 goto out; 1251 } 1252 rc = PKCS11_CKR_OK; 1253 } 1254 1255 /* 1256 * All checks have passed. Create a copy of the serialized buffer which 1257 * holds the object attributes in @head_new for the new object 1258 */ 1259 template_size = sizeof(*obj->attributes) + obj->attributes->attrs_size; 1260 head_new = TEE_Malloc(template_size, TEE_MALLOC_FILL_ZERO); 1261 if (!head_new) { 1262 rc = PKCS11_CKR_DEVICE_MEMORY; 1263 goto out; 1264 } 1265 1266 TEE_MemMove(head_new, obj->attributes, template_size); 1267 1268 /* 1269 * Modify the copied attribute @head_new based on the template @head 1270 * given by the callee 1271 */ 1272 rc = modify_attributes_list(&head_new, head); 1273 if (rc) 1274 goto out; 1275 1276 /* Set key check value attribute */ 1277 rc = set_check_value_attr(&head_new); 1278 if (rc) 1279 goto out; 1280 1281 /* 1282 * At this stage the object is almost created: all its attributes are 1283 * referenced in @head_new, including the key value and are assumed 1284 * reliable. Now need to register it and get a handle for it. 1285 */ 1286 rc = create_object(session, head_new, &obj_handle); 1287 if (rc) 1288 goto out; 1289 1290 /* 1291 * Now obj_handle (through the related struct pkcs11_object 1292 * instance) owns the serialized buffer that holds the object 1293 * attributes. We clear reference in head to NULL as the serializer 1294 * object is now referred from obj_handle. This allows smooth pass 1295 * through free at function exit. 1296 */ 1297 head_new = NULL; 1298 1299 TEE_MemMove(out->memref.buffer, &obj_handle, sizeof(obj_handle)); 1300 out->memref.size = sizeof(obj_handle); 1301 1302 DMSG("PKCS11 session %"PRIu32": copy object %#"PRIx32, 1303 session->handle, obj_handle); 1304 1305 out: 1306 TEE_Free(head_new); 1307 TEE_Free(head); 1308 TEE_Free(template); 1309 return rc; 1310 } 1311