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 if (obj->key_handle != TEE_HANDLE_NULL) 89 TEE_FreeTransientObject(obj->key_handle); 90 91 if (obj->attribs_hdl != TEE_HANDLE_NULL) 92 TEE_CloseObject(obj->attribs_hdl); 93 94 TEE_Free(obj->attributes); 95 TEE_Free(obj->uuid); 96 TEE_Free(obj); 97 } 98 99 /* Release resources of a persistent object including volatile resources */ 100 void cleanup_persistent_object(struct pkcs11_object *obj, 101 struct ck_token *token) 102 { 103 TEE_Result res = TEE_SUCCESS; 104 105 if (!obj) 106 return; 107 108 /* Open handle with write properties to destroy the object */ 109 if (obj->attribs_hdl != TEE_HANDLE_NULL) 110 TEE_CloseObject(obj->attribs_hdl); 111 112 res = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE, 113 obj->uuid, sizeof(TEE_UUID), 114 TEE_DATA_FLAG_ACCESS_WRITE_META, 115 &obj->attribs_hdl); 116 if (!res) 117 TEE_CloseAndDeletePersistentObject1(obj->attribs_hdl); 118 119 obj->attribs_hdl = TEE_HANDLE_NULL; 120 destroy_object_uuid(token, obj); 121 122 LIST_REMOVE(obj, link); 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 LIST_REMOVE(obj, link); 144 145 if (session_only) { 146 /* Destroy object due to session closure */ 147 handle_put(get_object_handle_db(session), 148 pkcs11_object2handle(obj, session)); 149 cleanup_volatile_obj_ref(obj); 150 151 return; 152 } 153 154 /* Destroy target object (persistent or not) */ 155 if (get_bool(obj->attributes, PKCS11_CKA_TOKEN)) { 156 assert(obj->uuid); 157 /* Try twice otherwise panic! */ 158 if (unregister_persistent_object(session->token, obj->uuid) && 159 unregister_persistent_object(session->token, obj->uuid)) 160 TEE_Panic(0); 161 162 handle_put(get_object_handle_db(session), 163 pkcs11_object2handle(obj, session)); 164 cleanup_persistent_object(obj, session->token); 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 rc = PKCS11_CKR_OK; 284 } 285 286 *out_handle = obj_handle; 287 288 return PKCS11_CKR_OK; 289 err: 290 /* make sure that supplied "head" isn't freed */ 291 obj->attributes = NULL; 292 handle_put(get_object_handle_db(session), obj_handle); 293 if (get_bool(head, PKCS11_CKA_TOKEN)) 294 cleanup_persistent_object(obj, session->token); 295 else 296 cleanup_volatile_obj_ref(obj); 297 298 return rc; 299 } 300 301 enum pkcs11_rc entry_create_object(struct pkcs11_client *client, 302 uint32_t ptypes, TEE_Param *params) 303 { 304 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 305 TEE_PARAM_TYPE_NONE, 306 TEE_PARAM_TYPE_MEMREF_OUTPUT, 307 TEE_PARAM_TYPE_NONE); 308 enum pkcs11_rc rc = PKCS11_CKR_OK; 309 TEE_Param *ctrl = params; 310 TEE_Param *out = params + 2; 311 struct serialargs ctrlargs = { }; 312 struct pkcs11_session *session = NULL; 313 struct obj_attrs *head = NULL; 314 struct pkcs11_object_head *template = NULL; 315 size_t template_size = 0; 316 uint32_t obj_handle = 0; 317 318 /* 319 * Collect the arguments of the request 320 */ 321 322 if (!client || ptypes != exp_pt || 323 out->memref.size != sizeof(obj_handle)) 324 return PKCS11_CKR_ARGUMENTS_BAD; 325 326 serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 327 328 rc = serialargs_get_session_from_handle(&ctrlargs, client, &session); 329 if (rc) 330 return rc; 331 332 rc = serialargs_alloc_get_attributes(&ctrlargs, &template); 333 if (rc) 334 return rc; 335 336 if (serialargs_remaining_bytes(&ctrlargs)) { 337 rc = PKCS11_CKR_ARGUMENTS_BAD; 338 goto out; 339 } 340 341 template_size = sizeof(*template) + template->attrs_size; 342 343 /* 344 * Prepare a clean initial state for the requested object attributes. 345 * Free temporary template once done. 346 */ 347 rc = create_attributes_from_template(&head, template, template_size, 348 NULL, PKCS11_FUNCTION_IMPORT, 349 PKCS11_PROCESSING_IMPORT, 350 PKCS11_CKO_UNDEFINED_ID); 351 TEE_Free(template); 352 template = NULL; 353 if (rc) 354 goto out; 355 356 /* 357 * Check target object attributes match target processing 358 * Check target object attributes match token state 359 */ 360 rc = check_created_attrs_against_processing(PKCS11_PROCESSING_IMPORT, 361 head); 362 if (rc) 363 goto out; 364 365 rc = check_created_attrs_against_token(session, head); 366 if (rc) 367 goto out; 368 369 rc = check_access_attrs_against_token(session, head); 370 if (rc) 371 goto out; 372 373 /* 374 * At this stage the object is almost created: all its attributes are 375 * referenced in @head, including the key value and are assumed 376 * reliable. Now need to register it and get a handle for it. 377 */ 378 rc = create_object(session, head, &obj_handle); 379 if (rc) 380 goto out; 381 382 /* 383 * Now obj_handle (through the related struct pkcs11_object 384 * instance) owns the serialized buffer that holds the object 385 * attributes. We clear reference in head to NULL as the serializer 386 * object is now referred from obj_handle. This allows smooth pass 387 * through free at function exit. 388 */ 389 head = NULL; 390 391 TEE_MemMove(out->memref.buffer, &obj_handle, sizeof(obj_handle)); 392 out->memref.size = sizeof(obj_handle); 393 394 DMSG("PKCS11 session %"PRIu32": import object %#"PRIx32, 395 session->handle, obj_handle); 396 397 out: 398 TEE_Free(template); 399 TEE_Free(head); 400 401 return rc; 402 } 403 404 enum pkcs11_rc entry_destroy_object(struct pkcs11_client *client, 405 uint32_t ptypes, TEE_Param *params) 406 { 407 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 408 TEE_PARAM_TYPE_NONE, 409 TEE_PARAM_TYPE_NONE, 410 TEE_PARAM_TYPE_NONE); 411 enum pkcs11_rc rc = PKCS11_CKR_OK; 412 TEE_Param *ctrl = params; 413 struct serialargs ctrlargs = { }; 414 uint32_t object_handle = 0; 415 struct pkcs11_session *session = NULL; 416 struct pkcs11_object *object = NULL; 417 418 if (!client || ptypes != exp_pt) 419 return PKCS11_CKR_ARGUMENTS_BAD; 420 421 serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 422 423 rc = serialargs_get_session_from_handle(&ctrlargs, client, &session); 424 if (rc) 425 return rc; 426 427 rc = serialargs_get_u32(&ctrlargs, &object_handle); 428 if (rc) 429 return rc; 430 431 if (serialargs_remaining_bytes(&ctrlargs)) 432 return PKCS11_CKR_ARGUMENTS_BAD; 433 434 object = pkcs11_handle2object(object_handle, session); 435 if (!object) 436 return PKCS11_CKR_OBJECT_HANDLE_INVALID; 437 438 /* Only session objects can be destroyed during a read-only session */ 439 if (get_bool(object->attributes, PKCS11_CKA_TOKEN) && 440 !pkcs11_session_is_read_write(session)) { 441 DMSG("Can't destroy persistent object"); 442 return PKCS11_CKR_SESSION_READ_ONLY; 443 } 444 445 /* 446 * Only public objects can be destroyed unless normal user is logged in 447 */ 448 rc = check_access_attrs_against_token(session, object->attributes); 449 if (rc) 450 return PKCS11_CKR_USER_NOT_LOGGED_IN; 451 452 /* Objects with PKCS11_CKA_DESTROYABLE as false aren't destroyable */ 453 if (!get_bool(object->attributes, PKCS11_CKA_DESTROYABLE)) 454 return PKCS11_CKR_ACTION_PROHIBITED; 455 456 destroy_object(session, object, false); 457 458 DMSG("PKCS11 session %"PRIu32": destroy object %#"PRIx32, 459 session->handle, object_handle); 460 461 return rc; 462 } 463 464 static void release_find_obj_context(struct pkcs11_find_objects *find_ctx) 465 { 466 if (!find_ctx) 467 return; 468 469 TEE_Free(find_ctx->attributes); 470 TEE_Free(find_ctx->handles); 471 TEE_Free(find_ctx); 472 } 473 474 static enum pkcs11_rc find_ctx_add(struct pkcs11_find_objects *find_ctx, 475 uint32_t handle) 476 { 477 uint32_t *hdls = TEE_Realloc(find_ctx->handles, 478 (find_ctx->count + 1) * sizeof(*hdls)); 479 480 if (!hdls) 481 return PKCS11_CKR_DEVICE_MEMORY; 482 483 find_ctx->handles = hdls; 484 485 *(find_ctx->handles + find_ctx->count) = handle; 486 find_ctx->count++; 487 488 return PKCS11_CKR_OK; 489 } 490 491 enum pkcs11_rc entry_find_objects_init(struct pkcs11_client *client, 492 uint32_t ptypes, TEE_Param *params) 493 { 494 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 495 TEE_PARAM_TYPE_NONE, 496 TEE_PARAM_TYPE_NONE, 497 TEE_PARAM_TYPE_NONE); 498 TEE_Param *ctrl = params; 499 enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR; 500 struct serialargs ctrlargs = { }; 501 struct pkcs11_session *session = NULL; 502 struct pkcs11_session *sess = NULL; 503 struct pkcs11_object_head *template = NULL; 504 struct obj_attrs *req_attrs = NULL; 505 struct pkcs11_object *obj = NULL; 506 struct pkcs11_find_objects *find_ctx = NULL; 507 struct handle_db *object_db = NULL; 508 509 if (!client || ptypes != exp_pt) 510 return PKCS11_CKR_ARGUMENTS_BAD; 511 512 serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 513 514 rc = serialargs_get_session_from_handle(&ctrlargs, client, &session); 515 if (rc) 516 return rc; 517 518 rc = serialargs_alloc_get_attributes(&ctrlargs, &template); 519 if (rc) 520 return rc; 521 522 if (serialargs_remaining_bytes(&ctrlargs)) { 523 rc = PKCS11_CKR_ARGUMENTS_BAD; 524 goto out; 525 } 526 527 /* Search objects only if no operation is on-going */ 528 if (session_is_active(session)) { 529 rc = PKCS11_CKR_OPERATION_ACTIVE; 530 goto out; 531 } 532 533 if (session->find_ctx) { 534 EMSG("Active object search already in progress"); 535 rc = PKCS11_CKR_FUNCTION_FAILED; 536 goto out; 537 } 538 539 rc = sanitize_client_object(&req_attrs, template, 540 sizeof(*template) + template->attrs_size, 541 PKCS11_UNDEFINED_ID, PKCS11_UNDEFINED_ID); 542 if (rc) 543 goto out; 544 545 /* Must zero init the structure */ 546 find_ctx = TEE_Malloc(sizeof(*find_ctx), TEE_MALLOC_FILL_ZERO); 547 if (!find_ctx) { 548 rc = PKCS11_CKR_DEVICE_MEMORY; 549 goto out; 550 } 551 552 TEE_Free(template); 553 template = NULL; 554 555 switch (get_class(req_attrs)) { 556 case PKCS11_CKO_UNDEFINED_ID: 557 /* Unspecified class searches among data objects */ 558 case PKCS11_CKO_SECRET_KEY: 559 case PKCS11_CKO_PUBLIC_KEY: 560 case PKCS11_CKO_PRIVATE_KEY: 561 case PKCS11_CKO_DATA: 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 return PKCS11_CKR_GENERAL_ERROR; 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