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