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 /* Release resources of a non-persistent object */ 44 static void cleanup_volatile_obj_ref(struct pkcs11_object *obj) 45 { 46 if (!obj) 47 return; 48 49 if (obj->key_handle != TEE_HANDLE_NULL) 50 TEE_FreeTransientObject(obj->key_handle); 51 52 if (obj->attribs_hdl != TEE_HANDLE_NULL) 53 TEE_CloseObject(obj->attribs_hdl); 54 55 TEE_Free(obj->attributes); 56 TEE_Free(obj->uuid); 57 TEE_Free(obj); 58 } 59 60 /* Release resources of a persistent object including volatile resources */ 61 static void cleanup_persistent_object(struct pkcs11_object *obj __unused, 62 struct ck_token *token __unused) 63 { 64 EMSG("Persistent object not yet supported, panic!"); 65 TEE_Panic(0); 66 } 67 68 /* 69 * destroy_object - destroy an PKCS11 TA object 70 * 71 * @session - session requesting object destruction 72 * @obj - reference to the PKCS11 TA object 73 * @session_only - true if only session object shall be destroyed 74 */ 75 void destroy_object(struct pkcs11_session *session, struct pkcs11_object *obj, 76 bool session_only) 77 { 78 #ifdef DEBUG 79 trace_attributes("[destroy]", obj->attributes); 80 if (obj->uuid) 81 MSG_RAW("[destroy] obj uuid %pUl", (void *)obj->uuid); 82 #endif 83 84 /* 85 * Remove from session list only if it was published. 86 * 87 * This depends on obj->link.le_prev always pointing on the 88 * link.le_next element in the previous object in the list even if 89 * there's only a single object in the list. In the first object in 90 * the list obj->link.le_prev instead points to lh_first in the 91 * list head. If list implementation is changed we need to revisit 92 * this. 93 */ 94 if (obj->link.le_next || obj->link.le_prev) 95 LIST_REMOVE(obj, link); 96 97 if (session_only) { 98 /* Destroy object due to session closure */ 99 handle_put(&session->object_handle_db, 100 pkcs11_object2handle(obj, session)); 101 cleanup_volatile_obj_ref(obj); 102 103 return; 104 } 105 106 /* Destroy target object (persistent or not) */ 107 if (get_bool(obj->attributes, PKCS11_CKA_TOKEN)) { 108 EMSG("Persistent object not yet supported, panic!"); 109 TEE_Panic(0); 110 } else { 111 handle_put(&session->object_handle_db, 112 pkcs11_object2handle(obj, session)); 113 cleanup_volatile_obj_ref(obj); 114 } 115 } 116 117 static struct pkcs11_object *create_obj_instance(struct obj_attrs *head) 118 { 119 struct pkcs11_object *obj = NULL; 120 121 obj = TEE_Malloc(sizeof(struct pkcs11_object), TEE_MALLOC_FILL_ZERO); 122 if (!obj) 123 return NULL; 124 125 obj->key_handle = TEE_HANDLE_NULL; 126 obj->attribs_hdl = TEE_HANDLE_NULL; 127 obj->attributes = head; 128 129 return obj; 130 } 131 132 /* 133 * create_object - create an PKCS11 TA object from its attributes and value 134 * 135 * @sess - session requesting object creation 136 * @head - reference to serialized attributes 137 * @out_handle - generated handle for the created object 138 */ 139 enum pkcs11_rc create_object(void *sess, struct obj_attrs *head, 140 uint32_t *out_handle) 141 { 142 enum pkcs11_rc rc = 0; 143 struct pkcs11_object *obj = NULL; 144 struct pkcs11_session *session = (struct pkcs11_session *)sess; 145 uint32_t obj_handle = 0; 146 147 #ifdef DEBUG 148 trace_attributes("[create]", head); 149 #endif 150 151 /* 152 * We do not check the key attributes. At this point, key attributes 153 * are expected consistent and reliable. 154 */ 155 156 obj = create_obj_instance(head); 157 if (!obj) 158 return PKCS11_CKR_DEVICE_MEMORY; 159 160 /* Create a handle for the object in the session database */ 161 obj_handle = handle_get(&session->object_handle_db, obj); 162 if (!obj_handle) { 163 rc = PKCS11_CKR_DEVICE_MEMORY; 164 goto err; 165 } 166 167 if (get_bool(obj->attributes, PKCS11_CKA_TOKEN)) { 168 EMSG("Persistent object not yet supported, panic!"); 169 TEE_Panic(0); 170 } else { 171 rc = PKCS11_CKR_OK; 172 LIST_INSERT_HEAD(get_session_objects(session), obj, link); 173 } 174 175 *out_handle = obj_handle; 176 177 return PKCS11_CKR_OK; 178 err: 179 /* make sure that supplied "head" isn't freed */ 180 obj->attributes = NULL; 181 handle_put(&session->object_handle_db, obj_handle); 182 if (get_bool(head, PKCS11_CKA_TOKEN)) 183 cleanup_persistent_object(obj, session->token); 184 else 185 cleanup_volatile_obj_ref(obj); 186 187 return rc; 188 } 189 190 enum pkcs11_rc entry_create_object(struct pkcs11_client *client, 191 uint32_t ptypes, TEE_Param *params) 192 { 193 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 194 TEE_PARAM_TYPE_NONE, 195 TEE_PARAM_TYPE_MEMREF_OUTPUT, 196 TEE_PARAM_TYPE_NONE); 197 enum pkcs11_rc rc = PKCS11_CKR_OK; 198 TEE_Param *ctrl = params; 199 TEE_Param *out = params + 2; 200 struct serialargs ctrlargs = { }; 201 struct pkcs11_session *session = NULL; 202 struct obj_attrs *head = NULL; 203 struct pkcs11_object_head *template = NULL; 204 uint32_t session_handle = 0; 205 size_t template_size = 0; 206 uint32_t obj_handle = 0; 207 208 /* 209 * Collect the arguments of the request 210 */ 211 212 if (!client || ptypes != exp_pt || 213 out->memref.size != sizeof(obj_handle)) 214 return PKCS11_CKR_ARGUMENTS_BAD; 215 216 serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 217 218 rc = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t)); 219 if (rc) 220 return rc; 221 222 rc = serialargs_alloc_get_attributes(&ctrlargs, &template); 223 if (rc) 224 return rc; 225 226 if (serialargs_remaining_bytes(&ctrlargs)) { 227 rc = PKCS11_CKR_ARGUMENTS_BAD; 228 goto out; 229 } 230 231 session = pkcs11_handle2session(session_handle, client); 232 if (!session) { 233 rc = PKCS11_CKR_SESSION_HANDLE_INVALID; 234 goto out; 235 } 236 237 template_size = sizeof(*template) + template->attrs_size; 238 239 /* 240 * Prepare a clean initial state for the requested object attributes. 241 * Free temporary template once done. 242 */ 243 rc = create_attributes_from_template(&head, template, template_size, 244 NULL, PKCS11_FUNCTION_IMPORT, 245 PKCS11_PROCESSING_IMPORT); 246 TEE_Free(template); 247 template = NULL; 248 if (rc) 249 goto out; 250 251 /* 252 * Check target object attributes match target processing 253 * Check target object attributes match token state 254 */ 255 rc = check_created_attrs_against_processing(PKCS11_PROCESSING_IMPORT, 256 head); 257 if (rc) 258 goto out; 259 260 rc = check_created_attrs_against_token(session, head); 261 if (rc) 262 goto out; 263 264 /* 265 * At this stage the object is almost created: all its attributes are 266 * referenced in @head, including the key value and are assumed 267 * reliable. Now need to register it and get a handle for it. 268 */ 269 rc = create_object(session, head, &obj_handle); 270 if (rc) 271 goto out; 272 273 /* 274 * Now obj_handle (through the related struct pkcs11_object 275 * instance) owns the serialised buffer that holds the object 276 * attributes. We clear reference in head to NULL as the serializer 277 * object is now referred from obj_handle. This allows smooth pass 278 * through free at function exit. 279 */ 280 head = NULL; 281 282 TEE_MemMove(out->memref.buffer, &obj_handle, sizeof(obj_handle)); 283 out->memref.size = sizeof(obj_handle); 284 285 DMSG("PKCS11 session %"PRIu32": import object %#"PRIx32, 286 session->handle, obj_handle); 287 288 out: 289 TEE_Free(template); 290 TEE_Free(head); 291 292 return rc; 293 } 294 295 enum pkcs11_rc entry_destroy_object(struct pkcs11_client *client, 296 uint32_t ptypes, TEE_Param *params) 297 { 298 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 299 TEE_PARAM_TYPE_NONE, 300 TEE_PARAM_TYPE_NONE, 301 TEE_PARAM_TYPE_NONE); 302 enum pkcs11_rc rc = PKCS11_CKR_OK; 303 TEE_Param *ctrl = params; 304 struct serialargs ctrlargs = { }; 305 uint32_t object_handle = 0; 306 struct pkcs11_session *session = NULL; 307 struct pkcs11_object *object = NULL; 308 uint32_t session_handle = 0; 309 310 if (!client || ptypes != exp_pt) 311 return PKCS11_CKR_ARGUMENTS_BAD; 312 313 serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); 314 315 rc = serialargs_get_u32(&ctrlargs, &session_handle); 316 if (rc) 317 return rc; 318 319 rc = serialargs_get_u32(&ctrlargs, &object_handle); 320 if (rc) 321 return rc; 322 323 if (serialargs_remaining_bytes(&ctrlargs)) 324 return PKCS11_CKR_ARGUMENTS_BAD; 325 326 session = pkcs11_handle2session(session_handle, client); 327 if (!session) 328 return PKCS11_CKR_SESSION_HANDLE_INVALID; 329 330 object = pkcs11_handle2object(object_handle, session); 331 if (!object) 332 return PKCS11_CKR_OBJECT_HANDLE_INVALID; 333 334 destroy_object(session, object, false); 335 336 DMSG("PKCS11 session %"PRIu32": destroy object %#"PRIx32, 337 session->handle, object_handle); 338 339 return rc; 340 } 341