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 static 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 = 0; 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 LIST_INSERT_HEAD(&session->token->object_list, obj, link); 248 } else { 249 rc = PKCS11_CKR_OK; 250 LIST_INSERT_HEAD(get_session_objects(session), obj, link); 251 } 252 253 *out_handle = obj_handle; 254 255 return PKCS11_CKR_OK; 256 err: 257 /* make sure that supplied "head" isn't freed */ 258 obj->attributes = NULL; 259 handle_put(&session->object_handle_db, obj_handle); 260 if (get_bool(head, PKCS11_CKA_TOKEN)) 261 cleanup_persistent_object(obj, session->token); 262 else 263 cleanup_volatile_obj_ref(obj); 264 265 return rc; 266 } 267 268 enum pkcs11_rc entry_create_object(struct pkcs11_client *client, 269 uint32_t ptypes, TEE_Param *params) 270 { 271 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 272 TEE_PARAM_TYPE_NONE, 273 TEE_PARAM_TYPE_MEMREF_OUTPUT, 274 TEE_PARAM_TYPE_NONE); 275 enum pkcs11_rc rc = PKCS11_CKR_OK; 276 TEE_Param *ctrl = params; 277 TEE_Param *out = params + 2; 278 struct serialargs ctrlargs = { }; 279 struct pkcs11_session *session = NULL; 280 struct obj_attrs *head = NULL; 281 struct pkcs11_object_head *template = NULL; 282 uint32_t session_handle = 0; 283 size_t template_size = 0; 284 uint32_t obj_handle = 0; 285 286 /* 287 * Collect the arguments of the request 288 */ 289 290 if (!client || ptypes != exp_pt || 291 out->memref.size != sizeof(obj_handle)) 292 return PKCS11_CKR_ARGUMENTS_BAD; 293 294 serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 295 296 rc = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t)); 297 if (rc) 298 return rc; 299 300 rc = serialargs_alloc_get_attributes(&ctrlargs, &template); 301 if (rc) 302 return rc; 303 304 if (serialargs_remaining_bytes(&ctrlargs)) { 305 rc = PKCS11_CKR_ARGUMENTS_BAD; 306 goto out; 307 } 308 309 session = pkcs11_handle2session(session_handle, client); 310 if (!session) { 311 rc = PKCS11_CKR_SESSION_HANDLE_INVALID; 312 goto out; 313 } 314 315 template_size = sizeof(*template) + template->attrs_size; 316 317 /* 318 * Prepare a clean initial state for the requested object attributes. 319 * Free temporary template once done. 320 */ 321 rc = create_attributes_from_template(&head, template, template_size, 322 NULL, PKCS11_FUNCTION_IMPORT, 323 PKCS11_PROCESSING_IMPORT); 324 TEE_Free(template); 325 template = NULL; 326 if (rc) 327 goto out; 328 329 /* 330 * Check target object attributes match target processing 331 * Check target object attributes match token state 332 */ 333 rc = check_created_attrs_against_processing(PKCS11_PROCESSING_IMPORT, 334 head); 335 if (rc) 336 goto out; 337 338 rc = check_created_attrs_against_token(session, head); 339 if (rc) 340 goto out; 341 342 /* 343 * At this stage the object is almost created: all its attributes are 344 * referenced in @head, including the key value and are assumed 345 * reliable. Now need to register it and get a handle for it. 346 */ 347 rc = create_object(session, head, &obj_handle); 348 if (rc) 349 goto out; 350 351 /* 352 * Now obj_handle (through the related struct pkcs11_object 353 * instance) owns the serialised buffer that holds the object 354 * attributes. We clear reference in head to NULL as the serializer 355 * object is now referred from obj_handle. This allows smooth pass 356 * through free at function exit. 357 */ 358 head = NULL; 359 360 TEE_MemMove(out->memref.buffer, &obj_handle, sizeof(obj_handle)); 361 out->memref.size = sizeof(obj_handle); 362 363 DMSG("PKCS11 session %"PRIu32": import object %#"PRIx32, 364 session->handle, obj_handle); 365 366 out: 367 TEE_Free(template); 368 TEE_Free(head); 369 370 return rc; 371 } 372 373 enum pkcs11_rc entry_destroy_object(struct pkcs11_client *client, 374 uint32_t ptypes, TEE_Param *params) 375 { 376 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 377 TEE_PARAM_TYPE_NONE, 378 TEE_PARAM_TYPE_NONE, 379 TEE_PARAM_TYPE_NONE); 380 enum pkcs11_rc rc = PKCS11_CKR_OK; 381 TEE_Param *ctrl = params; 382 struct serialargs ctrlargs = { }; 383 uint32_t object_handle = 0; 384 struct pkcs11_session *session = NULL; 385 struct pkcs11_object *object = NULL; 386 uint32_t session_handle = 0; 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_u32(&ctrlargs, &session_handle); 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 session = pkcs11_handle2session(session_handle, client); 405 if (!session) 406 return PKCS11_CKR_SESSION_HANDLE_INVALID; 407 408 object = pkcs11_handle2object(object_handle, session); 409 if (!object) 410 return PKCS11_CKR_OBJECT_HANDLE_INVALID; 411 412 destroy_object(session, object, false); 413 414 DMSG("PKCS11 session %"PRIu32": destroy object %#"PRIx32, 415 session->handle, object_handle); 416 417 return rc; 418 } 419