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