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