xref: /optee_os/ta/pkcs11/src/object.c (revision b56b3d071d79537f0b9c86d26c033d9ed5c0206a)
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