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 size_t template_size = 0; 283 uint32_t obj_handle = 0; 284 285 /* 286 * Collect the arguments of the request 287 */ 288 289 if (!client || ptypes != exp_pt || 290 out->memref.size != sizeof(obj_handle)) 291 return PKCS11_CKR_ARGUMENTS_BAD; 292 293 serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 294 295 rc = serialargs_get_session_from_handle(&ctrlargs, client, &session); 296 if (rc) 297 return rc; 298 299 rc = serialargs_alloc_get_attributes(&ctrlargs, &template); 300 if (rc) 301 return rc; 302 303 if (serialargs_remaining_bytes(&ctrlargs)) { 304 rc = PKCS11_CKR_ARGUMENTS_BAD; 305 goto out; 306 } 307 308 template_size = sizeof(*template) + template->attrs_size; 309 310 /* 311 * Prepare a clean initial state for the requested object attributes. 312 * Free temporary template once done. 313 */ 314 rc = create_attributes_from_template(&head, template, template_size, 315 NULL, PKCS11_FUNCTION_IMPORT, 316 PKCS11_PROCESSING_IMPORT); 317 TEE_Free(template); 318 template = NULL; 319 if (rc) 320 goto out; 321 322 /* 323 * Check target object attributes match target processing 324 * Check target object attributes match token state 325 */ 326 rc = check_created_attrs_against_processing(PKCS11_PROCESSING_IMPORT, 327 head); 328 if (rc) 329 goto out; 330 331 rc = check_created_attrs_against_token(session, head); 332 if (rc) 333 goto out; 334 335 /* 336 * At this stage the object is almost created: all its attributes are 337 * referenced in @head, including the key value and are assumed 338 * reliable. Now need to register it and get a handle for it. 339 */ 340 rc = create_object(session, head, &obj_handle); 341 if (rc) 342 goto out; 343 344 /* 345 * Now obj_handle (through the related struct pkcs11_object 346 * instance) owns the serialised buffer that holds the object 347 * attributes. We clear reference in head to NULL as the serializer 348 * object is now referred from obj_handle. This allows smooth pass 349 * through free at function exit. 350 */ 351 head = NULL; 352 353 TEE_MemMove(out->memref.buffer, &obj_handle, sizeof(obj_handle)); 354 out->memref.size = sizeof(obj_handle); 355 356 DMSG("PKCS11 session %"PRIu32": import object %#"PRIx32, 357 session->handle, obj_handle); 358 359 out: 360 TEE_Free(template); 361 TEE_Free(head); 362 363 return rc; 364 } 365 366 enum pkcs11_rc entry_destroy_object(struct pkcs11_client *client, 367 uint32_t ptypes, TEE_Param *params) 368 { 369 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 370 TEE_PARAM_TYPE_NONE, 371 TEE_PARAM_TYPE_NONE, 372 TEE_PARAM_TYPE_NONE); 373 enum pkcs11_rc rc = PKCS11_CKR_OK; 374 TEE_Param *ctrl = params; 375 struct serialargs ctrlargs = { }; 376 uint32_t object_handle = 0; 377 struct pkcs11_session *session = NULL; 378 struct pkcs11_object *object = NULL; 379 380 if (!client || ptypes != exp_pt) 381 return PKCS11_CKR_ARGUMENTS_BAD; 382 383 serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 384 385 rc = serialargs_get_session_from_handle(&ctrlargs, client, &session); 386 if (rc) 387 return rc; 388 389 rc = serialargs_get_u32(&ctrlargs, &object_handle); 390 if (rc) 391 return rc; 392 393 if (serialargs_remaining_bytes(&ctrlargs)) 394 return PKCS11_CKR_ARGUMENTS_BAD; 395 396 object = pkcs11_handle2object(object_handle, session); 397 if (!object) 398 return PKCS11_CKR_OBJECT_HANDLE_INVALID; 399 400 destroy_object(session, object, false); 401 402 DMSG("PKCS11 session %"PRIu32": destroy object %#"PRIx32, 403 session->handle, object_handle); 404 405 return rc; 406 } 407