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