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