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