1 /*
2  * gnome-keyring
3  *
4  * Copyright (C) 2008 Stefan Walter
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, see
18  * <http://www.gnu.org/licenses/>.
19  */
20 
21 #include "config.h"
22 
23 #include "pkcs11/pkcs11.h"
24 #include "pkcs11/pkcs11i.h"
25 
26 #include "gkm-attributes.h"
27 #include "gkm-credential.h"
28 #include "gkm-crypto.h"
29 #include "gkm-factory.h"
30 #include "gkm-manager.h"
31 #include "gkm-memory-store.h"
32 #include "gkm-session.h"
33 #include "gkm-sexp.h"
34 #include "gkm-sexp-key.h"
35 #include "gkm-transaction.h"
36 #include "gkm-util.h"
37 
38 enum {
39 	PROP_0,
40 	PROP_MODULE,
41 	PROP_SLOT_ID,
42 	PROP_APARTMENT,
43 	PROP_HANDLE,
44 	PROP_FLAGS,
45 	PROP_MANAGER,
46 	PROP_LOGGED_IN
47 };
48 
49 struct _GkmSessionPrivate {
50 
51 	CK_SESSION_HANDLE handle;
52 	CK_SLOT_ID slot_id;
53 	CK_ULONG apartment;
54 
55 	GkmModule *module;
56 	GkmManager *manager;
57 	GkmStore *store;
58 
59 	CK_USER_TYPE logged_in;
60 	CK_ULONG flags;
61 
62 	CK_NOTIFY notify_callback;
63 	CK_VOID_PTR application_ptr;
64 
65 	/* Objects owned by this session */
66 	GHashTable *objects;
67 
68 	/* Used for operations */
69 	void (*current_operation) (GkmSession *self);
70 	GkmObject *current_object;
71 	GkmCredential *credential;
72 
73 	/* Used for find operations */
74 	GArray *found_objects;
75 
76 	/* Used for crypto operations */
77 	gpointer crypto_state;
78 	GDestroyNotify crypto_destroy;
79 	CK_MECHANISM_TYPE crypto_mechanism;
80 	CK_ATTRIBUTE_TYPE crypto_method;
81 };
82 
83 G_DEFINE_TYPE_WITH_PRIVATE (GkmSession, gkm_session, G_TYPE_OBJECT);
84 
85 static void add_object (GkmSession *self, GkmTransaction *transaction, GkmObject *object);
86 static void remove_object (GkmSession *self, GkmTransaction *transaction, GkmObject *object);
87 
88 /* -----------------------------------------------------------------------------
89  * INTERNAL
90  */
91 
92 static void
cleanup_crypto(GkmSession * self)93 cleanup_crypto (GkmSession *self)
94 {
95 	g_assert (self->pv->current_operation == cleanup_crypto);
96 
97 	if (self->pv->crypto_state && self->pv->crypto_destroy)
98 		(self->pv->crypto_destroy) (self->pv->crypto_state);
99 	self->pv->crypto_state = NULL;
100 	self->pv->crypto_destroy = NULL;
101 	self->pv->crypto_mechanism = 0;
102 	self->pv->crypto_method = 0;
103 
104 	g_assert (GKM_IS_OBJECT (self->pv->current_object));
105 	if (self->pv->current_object)
106 		g_object_unref (self->pv->current_object);
107 	self->pv->current_object = NULL;
108 
109 	if (self->pv->credential) {
110 		g_object_set_data (G_OBJECT (self->pv->credential), "owned-by-session", NULL);
111 		g_object_unref (self->pv->credential);
112 		self->pv->credential = NULL;
113 	}
114 
115 	self->pv->current_operation = NULL;
116 }
117 
118 static CK_RV
prepare_crypto(GkmSession * self,CK_MECHANISM_PTR mech,CK_ATTRIBUTE_TYPE method,CK_OBJECT_HANDLE handle)119 prepare_crypto (GkmSession *self, CK_MECHANISM_PTR mech,
120                 CK_ATTRIBUTE_TYPE method, CK_OBJECT_HANDLE handle)
121 {
122 	GkmObject *object;
123 	CK_MECHANISM_TYPE_PTR mechanisms;
124 	CK_ULONG n_mechanisms, i;
125 	gsize n_data;
126 	gboolean have;
127 	gulong key_type;
128 	CK_RV rv;
129 
130 	g_assert (GKM_IS_SESSION (self));
131 
132 	/* Cancel any current operation */
133 	if (self->pv->current_operation) {
134 		(self->pv->current_operation) (self);
135 		g_assert (!self->pv->current_operation);
136 	}
137 
138 	g_assert (!self->pv->crypto_state);
139 
140 	/* First find the object */
141 	rv = gkm_session_lookup_readable_object (self, handle, &object);
142 	if (rv != CKR_OK)
143 		return rv;
144 
145 	/* Make sure it's a key */
146 	if (!gkm_object_get_attribute_ulong (object, self, CKA_KEY_TYPE, &key_type))
147 		return CKR_KEY_HANDLE_INVALID;
148 
149 	/* Lookup the mechanisms this object can do */
150 	mechanisms = gkm_object_get_attribute_data (object, self, CKA_ALLOWED_MECHANISMS, &n_data);
151 	if (mechanisms)
152 		n_mechanisms = n_data / sizeof (CK_MECHANISM_TYPE);
153 	else
154 		n_mechanisms = 0;
155 
156 	/* See if ours is represented */
157 	have = FALSE;
158 	for (i = 0; !have && i < n_mechanisms; ++i) {
159 		if (mechanisms[i] == mech->mechanism)
160 			have = TRUE;
161 	}
162 
163 	g_free (mechanisms);
164 
165 	if (have == FALSE)
166 		return CKR_KEY_TYPE_INCONSISTENT;
167 
168 	/* Check that the object can do this method */
169 	if (!gkm_object_get_attribute_boolean (object, self, method, &have) || !have)
170 		return CKR_KEY_FUNCTION_NOT_PERMITTED;
171 
172 	/* Track the cyrpto object */
173 	self->pv->current_object = object;
174 	g_object_ref (object);
175 
176 	/* And note what we're setup for */
177 	self->pv->current_operation = cleanup_crypto;
178 	self->pv->crypto_mechanism = mech->mechanism;
179 	self->pv->crypto_method = method;
180 
181 	return CKR_OK;
182 }
183 
184 static CK_RV
process_crypto(GkmSession * self,CK_ATTRIBUTE_TYPE method,CK_BYTE_PTR bufone,CK_ULONG n_bufone,CK_BYTE_PTR buftwo,CK_ULONG_PTR n_buftwo)185 process_crypto (GkmSession *self, CK_ATTRIBUTE_TYPE method, CK_BYTE_PTR bufone,
186                 CK_ULONG n_bufone, CK_BYTE_PTR buftwo, CK_ULONG_PTR n_buftwo)
187 {
188 	CK_RV rv = CKR_OK;
189 
190 	g_assert (GKM_IS_SESSION (self));
191 
192 	if (self->pv->current_operation != cleanup_crypto)
193 		return CKR_OPERATION_NOT_INITIALIZED;
194 	if (method != self->pv->crypto_method)
195 		return CKR_OPERATION_NOT_INITIALIZED;
196 
197 	if (!bufone || !n_buftwo)
198 		rv = CKR_ARGUMENTS_BAD;
199 
200 	if (rv == CKR_OK) {
201 		/* Load up the actual sexp we're going to use */
202 		if (!self->pv->crypto_state) {
203 			g_return_val_if_fail (GKM_IS_OBJECT (self->pv->current_object), CKR_GENERAL_ERROR);
204 			rv = gkm_crypto_prepare (self, self->pv->crypto_mechanism, self->pv->current_object);
205 		}
206 	}
207 
208 	if (rv == CKR_OK) {
209 		g_assert (self->pv->crypto_mechanism);
210 		rv = gkm_crypto_perform (self, self->pv->crypto_mechanism, method,
211 		                         bufone, n_bufone, buftwo, n_buftwo);
212 	}
213 
214 	/* Under these conditions the operation isn't complete */
215 	if (rv == CKR_BUFFER_TOO_SMALL || rv == CKR_USER_NOT_LOGGED_IN ||
216 	    (rv == CKR_OK && buftwo == NULL))
217 		return rv;
218 
219 	cleanup_crypto (self);
220 	return rv;
221 }
222 
223 static void
cleanup_found(GkmSession * self)224 cleanup_found (GkmSession *self)
225 {
226 	g_assert (GKM_IS_SESSION (self));
227 
228 	g_assert (self->pv->found_objects);
229 	g_array_free (self->pv->found_objects, TRUE);
230 	self->pv->found_objects = NULL;
231 
232 	self->pv->current_operation = NULL;
233 }
234 
235 static CK_RV
lookup_object_from_handle(GkmSession * self,CK_OBJECT_HANDLE handle,gboolean writable,GkmObject ** result)236 lookup_object_from_handle (GkmSession *self, CK_OBJECT_HANDLE handle,
237                            gboolean writable, GkmObject **result)
238 {
239 	GkmManager *manager;
240 	GkmObject *object;
241 	gboolean is_private;
242 	gboolean is_token;
243 
244 	g_return_val_if_fail (result, CKR_GENERAL_ERROR);
245 	g_return_val_if_fail (GKM_IS_SESSION (self), CKR_GENERAL_ERROR);
246 
247 	if (handle == 0)
248 		return CKR_OBJECT_HANDLE_INVALID;
249 
250 	/* Try looking up in the token manager */
251 	manager = gkm_module_get_manager (self->pv->module);
252 	object = gkm_manager_find_by_handle (manager, handle);
253 	is_token = TRUE;
254 
255 	/* Try looking up in the session manager */
256 	if (object == NULL) {
257 		manager = gkm_session_get_manager (self);
258 		object = gkm_manager_find_by_handle (manager, handle);
259 		is_token = FALSE;
260 	}
261 
262 	if (object == NULL)
263 		return CKR_OBJECT_HANDLE_INVALID;
264 
265 	g_return_val_if_fail (manager, CKR_GENERAL_ERROR);
266 
267 	/*
268 	 * Check that we're not accessing private objects on a
269 	 * non-logged in session
270 	 */
271 	if (self->pv->logged_in != CKU_USER) {
272 		if (!gkm_object_get_attribute_boolean (object, self, CKA_PRIVATE, &is_private))
273 			is_private = FALSE;
274 		if (is_private)
275 			return CKR_USER_NOT_LOGGED_IN;
276 	}
277 
278 	/*
279 	 * If we're going to write to this object check that we're in a
280 	 * writable session and object is modifiable.
281 	 */
282 	if (writable) {
283 		if (is_token) {
284 			if (!gkm_object_is_transient (object))
285 				if (gkm_module_get_write_protected (self->pv->module))
286 					return CKR_TOKEN_WRITE_PROTECTED;
287 			if (gkm_session_is_read_only (self))
288 				return CKR_SESSION_READ_ONLY;
289 		}
290 	}
291 
292 	*result = object;
293 	return CKR_OK;
294 }
295 
296 
297 static gboolean
complete_remove(GkmTransaction * transaction,GkmSession * self,GkmObject * object)298 complete_remove (GkmTransaction *transaction, GkmSession *self, GkmObject *object)
299 {
300 	if (gkm_transaction_get_failed (transaction))
301 		add_object (self, NULL, object);
302 	g_object_unref (object);
303 	return TRUE;
304 }
305 
306 static void
remove_object(GkmSession * self,GkmTransaction * transaction,GkmObject * object)307 remove_object (GkmSession *self, GkmTransaction *transaction, GkmObject *object)
308 {
309 	g_assert (GKM_IS_SESSION (self));
310 	g_assert (GKM_IS_OBJECT (object));
311 
312 	g_object_ref (object);
313 
314 	gkm_object_expose_full (object, transaction, FALSE);
315 	g_hash_table_remove (self->pv->objects, object);
316 	g_object_set (object, "store", NULL, NULL);
317 
318 	if (transaction)
319 		gkm_transaction_add (transaction, self, (GkmTransactionFunc)complete_remove,
320 		                     g_object_ref (object));
321 
322 	g_object_unref (object);
323 }
324 
325 static gboolean
complete_add(GkmTransaction * transaction,GkmSession * self,GkmObject * object)326 complete_add (GkmTransaction *transaction, GkmSession *self, GkmObject *object)
327 {
328 	if (gkm_transaction_get_failed (transaction))
329 		remove_object (self, NULL, object);
330 	g_object_unref (object);
331 	return TRUE;
332 }
333 
334 static void
add_object(GkmSession * self,GkmTransaction * transaction,GkmObject * object)335 add_object (GkmSession *self, GkmTransaction *transaction, GkmObject *object)
336 {
337 	g_assert (GKM_IS_SESSION (self));
338 	g_assert (GKM_IS_OBJECT (object));
339 
340 	/* Must not already be associated with a session or manager */
341 	g_return_if_fail (gkm_object_get_manager (object) == self->pv->manager);
342 	g_return_if_fail (g_object_get_data (G_OBJECT (object), "owned-by-session") == NULL);
343 	g_return_if_fail (g_hash_table_lookup (self->pv->objects, object) == NULL);
344 
345 	g_hash_table_insert (self->pv->objects, object, g_object_ref (object));
346 	g_object_set_data (G_OBJECT (object), "owned-by-session", self);
347 	g_object_set (object, "store", self->pv->store, NULL);
348 	gkm_object_expose_full (object, transaction, TRUE);
349 
350 	if (transaction)
351 		gkm_transaction_add (transaction, self, (GkmTransactionFunc)complete_add,
352 		                     g_object_ref (object));
353 }
354 
355 /* -----------------------------------------------------------------------------
356  * OBJECT
357  */
358 
359 
360 static GObject*
gkm_session_constructor(GType type,guint n_props,GObjectConstructParam * props)361 gkm_session_constructor (GType type, guint n_props, GObjectConstructParam *props)
362 {
363 	GkmSession *self = GKM_SESSION (G_OBJECT_CLASS (gkm_session_parent_class)->constructor(type, n_props, props));
364 	CK_ATTRIBUTE attr;
365 
366 	g_return_val_if_fail (self, NULL);
367 
368 	/* Register store attributes */
369 	attr.type = CKA_LABEL;
370 	attr.pValue = "";
371 	attr.ulValueLen = 0;
372 	gkm_store_register_schema (self->pv->store, &attr, NULL, 0);
373 
374 	return G_OBJECT (self);
375 }
376 
377 static void
gkm_session_init(GkmSession * self)378 gkm_session_init (GkmSession *self)
379 {
380 	self->pv = gkm_session_get_instance_private (self);
381 	self->pv->objects = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, gkm_util_dispose_unref);
382 	self->pv->flags = 0;
383 
384 	/* Create the store and register attributes */
385 	self->pv->store = GKM_STORE (gkm_memory_store_new ());
386 }
387 
388 static void
gkm_session_dispose(GObject * obj)389 gkm_session_dispose (GObject *obj)
390 {
391 	GkmSession *self = GKM_SESSION (obj);
392 
393 	/* Cleanup any current operation */
394 	if (self->pv->current_operation)
395 		(self->pv->current_operation) (self);
396 	g_assert (!self->pv->current_operation);
397 
398 	if (self->pv->module)
399 		g_object_unref (self->pv->module);
400 	self->pv->module = NULL;
401 
402 	if (self->pv->credential) {
403 		g_object_set_data (G_OBJECT (self->pv->credential), "owned-by-session", NULL);
404 		g_object_unref (self->pv->credential);
405 		self->pv->credential = NULL;
406 	}
407 
408 	g_hash_table_remove_all (self->pv->objects);
409 
410 	if (self->pv->manager)
411 		g_object_unref (self->pv->manager);
412 	self->pv->manager = NULL;
413 
414 	G_OBJECT_CLASS (gkm_session_parent_class)->dispose (obj);
415 }
416 
417 static void
gkm_session_finalize(GObject * obj)418 gkm_session_finalize (GObject *obj)
419 {
420 	GkmSession *self = GKM_SESSION (obj);
421 
422 	g_assert (self->pv->module == NULL);
423 	g_assert (self->pv->manager == NULL);
424 
425 	g_hash_table_destroy (self->pv->objects);
426 	self->pv->objects = NULL;
427 
428 	g_object_unref (self->pv->store);
429 	self->pv->store = NULL;
430 
431 	G_OBJECT_CLASS (gkm_session_parent_class)->finalize (obj);
432 }
433 
434 static void
gkm_session_set_property(GObject * obj,guint prop_id,const GValue * value,GParamSpec * pspec)435 gkm_session_set_property (GObject *obj, guint prop_id, const GValue *value,
436                            GParamSpec *pspec)
437 {
438 	GkmSession *self = GKM_SESSION (obj);
439 
440 	switch (prop_id) {
441 	case PROP_MODULE:
442 		g_return_if_fail (!self->pv->module);
443 		self->pv->module = g_value_get_object (value);
444 		g_return_if_fail (self->pv->module);
445 		g_object_ref (self->pv->module);
446 		break;
447 	case PROP_MANAGER:
448 		g_return_if_fail (!self->pv->manager);
449 		self->pv->manager = g_value_get_object (value);
450 		g_return_if_fail (self->pv->manager);
451 		g_object_ref (self->pv->manager);
452 		break;
453 	case PROP_SLOT_ID:
454 		self->pv->slot_id = g_value_get_ulong (value);
455 		break;
456 	case PROP_APARTMENT:
457 		self->pv->apartment = g_value_get_ulong (value);
458 		break;
459 	case PROP_HANDLE:
460 		self->pv->handle = g_value_get_ulong (value);
461 		g_return_if_fail (self->pv->handle != 0);
462 		break;
463 	case PROP_FLAGS:
464 		self->pv->flags = g_value_get_ulong (value);
465 		break;
466 	case PROP_LOGGED_IN:
467 		gkm_session_set_logged_in (self, g_value_get_ulong (value));
468 		break;
469 	default:
470 		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
471 		break;
472 	}
473 }
474 
475 static void
gkm_session_get_property(GObject * obj,guint prop_id,GValue * value,GParamSpec * pspec)476 gkm_session_get_property (GObject *obj, guint prop_id, GValue *value,
477                            GParamSpec *pspec)
478 {
479 	GkmSession *self = GKM_SESSION (obj);
480 
481 	switch (prop_id) {
482 	case PROP_MODULE:
483 		g_value_set_object (value, gkm_session_get_module (self));
484 		break;
485 	case PROP_MANAGER:
486 		g_value_set_object (value, gkm_session_get_manager (self));
487 		break;
488 	case PROP_SLOT_ID:
489 		g_value_set_ulong (value, gkm_session_get_slot_id (self));
490 		break;
491 	case PROP_APARTMENT:
492 		g_value_set_ulong (value, gkm_session_get_apartment (self));
493 		break;
494 	case PROP_HANDLE:
495 		g_value_set_ulong (value, gkm_session_get_handle (self));
496 		break;
497 	case PROP_FLAGS:
498 		g_value_set_ulong (value, self->pv->flags);
499 		break;
500 	case PROP_LOGGED_IN:
501 		g_value_set_ulong (value, gkm_session_get_logged_in (self));
502 		break;
503 	default:
504 		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
505 		break;
506 	}
507 }
508 
509 static void
gkm_session_class_init(GkmSessionClass * klass)510 gkm_session_class_init (GkmSessionClass *klass)
511 {
512 	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
513 
514 	gobject_class->constructor = gkm_session_constructor;
515 	gobject_class->dispose = gkm_session_dispose;
516 	gobject_class->finalize = gkm_session_finalize;
517 	gobject_class->set_property = gkm_session_set_property;
518 	gobject_class->get_property = gkm_session_get_property;
519 
520 	g_object_class_install_property (gobject_class, PROP_MODULE,
521 	         g_param_spec_object ("module", "Module", "Module this session belongs to",
522 	                              GKM_TYPE_MODULE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
523 
524 	g_object_class_install_property (gobject_class, PROP_MANAGER,
525 	         g_param_spec_object ("manager", "Manager", "Object manager for this session",
526 	                              GKM_TYPE_MANAGER, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
527 
528 	g_object_class_install_property (gobject_class, PROP_HANDLE,
529 	         g_param_spec_ulong ("handle", "Handle", "PKCS#11 session handle",
530 	                             0, G_MAXULONG, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
531 
532 	g_object_class_install_property (gobject_class, PROP_SLOT_ID,
533 	         g_param_spec_ulong ("slot-id", "Slot ID", "Slot ID this session is opened on",
534 	                             0, G_MAXULONG, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
535 
536 	g_object_class_install_property (gobject_class, PROP_APARTMENT,
537 	         g_param_spec_ulong ("apartment", "Apartment", "Apartment this session is opened on",
538 	                             0, G_MAXULONG, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
539 
540 	g_object_class_install_property(gobject_class, PROP_FLAGS,
541 	         g_param_spec_ulong ("flags", "Flags", "Flags for the session",
542 	                             0, G_MAXULONG, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
543 
544 	g_object_class_install_property (gobject_class, PROP_LOGGED_IN,
545 	         g_param_spec_ulong ("logged-in", "Logged in", "Whether this session is logged in or not",
546 	                             0, G_MAXULONG, CKU_NONE, G_PARAM_READWRITE));
547 }
548 
549 /* -----------------------------------------------------------------------------
550  * PUBLIC
551  */
552 
553 GkmSession*
gkm_session_for_session_object(GkmObject * obj)554 gkm_session_for_session_object (GkmObject *obj)
555 {
556 	g_return_val_if_fail (GKM_IS_OBJECT (obj), NULL);
557 	return GKM_SESSION (g_object_get_data (G_OBJECT (obj), "owned-by-session"));
558 }
559 
560 CK_SESSION_HANDLE
gkm_session_get_handle(GkmSession * self)561 gkm_session_get_handle (GkmSession *self)
562 {
563 	g_return_val_if_fail (GKM_IS_SESSION (self), 0);
564 	return self->pv->handle;
565 }
566 
567 CK_SLOT_ID
gkm_session_get_slot_id(GkmSession * self)568 gkm_session_get_slot_id (GkmSession *self)
569 {
570 	g_return_val_if_fail (GKM_IS_SESSION (self), 0);
571 	return self->pv->slot_id;
572 }
573 
574 CK_ULONG
gkm_session_get_apartment(GkmSession * self)575 gkm_session_get_apartment (GkmSession *self)
576 {
577 	g_return_val_if_fail (GKM_IS_SESSION (self), 0);
578 	return self->pv->apartment;
579 }
580 
581 GkmModule*
gkm_session_get_module(GkmSession * self)582 gkm_session_get_module (GkmSession *self)
583 {
584 	g_return_val_if_fail (GKM_IS_SESSION (self), NULL);
585 	g_return_val_if_fail (GKM_IS_MODULE (self->pv->module), NULL);
586 	return self->pv->module;
587 }
588 
589 GkmManager*
gkm_session_get_manager(GkmSession * self)590 gkm_session_get_manager (GkmSession *self)
591 {
592 	g_return_val_if_fail (GKM_IS_SESSION (self), NULL);
593 	g_return_val_if_fail (GKM_IS_MANAGER (self->pv->manager), NULL);
594 	return self->pv->manager;
595 }
596 
597 gulong
gkm_session_get_logged_in(GkmSession * self)598 gkm_session_get_logged_in (GkmSession *self)
599 {
600 	g_return_val_if_fail (GKM_IS_SESSION (self), FALSE);
601 	return self->pv->logged_in;
602 }
603 
604 void
gkm_session_set_logged_in(GkmSession * self,gulong logged_in)605 gkm_session_set_logged_in (GkmSession *self, gulong logged_in)
606 {
607 	g_return_if_fail (GKM_IS_SESSION (self));
608 	self->pv->logged_in = logged_in;
609 	g_object_notify (G_OBJECT (self), "logged-in");
610 }
611 
612 gpointer
gkm_session_get_crypto_state(GkmSession * self)613 gkm_session_get_crypto_state (GkmSession *self)
614 {
615 	g_return_val_if_fail (GKM_IS_SESSION (self), NULL);
616 	return self->pv->crypto_state;
617 }
618 
619 void
gkm_session_set_crypto_state(GkmSession * self,gpointer state,GDestroyNotify destroy)620 gkm_session_set_crypto_state (GkmSession *self, gpointer state,
621                               GDestroyNotify destroy)
622 {
623 	g_return_if_fail (GKM_IS_SESSION (self));
624 	if (self->pv->crypto_state != state) {
625 		if (self->pv->crypto_state && self->pv->crypto_destroy)
626 			(self->pv->crypto_destroy) (self->pv->crypto_state);
627 	}
628 	self->pv->crypto_state = state;
629 	self->pv->crypto_destroy = destroy;
630 }
631 
632 gboolean
gkm_session_is_read_only(GkmSession * self)633 gkm_session_is_read_only (GkmSession *self)
634 {
635 	g_return_val_if_fail (GKM_IS_SESSION (self), TRUE);
636 	return (self->pv->flags & CKF_RW_SESSION) ? FALSE : TRUE;
637 }
638 
639 gboolean
gkm_session_is_for_application(GkmSession * self)640 gkm_session_is_for_application (GkmSession *self)
641 {
642 	g_return_val_if_fail (GKM_IS_SESSION (self), TRUE);
643 	return (self->pv->flags & CKF_G_APPLICATION_SESSION) ? TRUE : FALSE;
644 }
645 
646 CK_RV
gkm_session_lookup_readable_object(GkmSession * self,CK_OBJECT_HANDLE handle,GkmObject ** result)647 gkm_session_lookup_readable_object (GkmSession *self, CK_OBJECT_HANDLE handle,
648                                     GkmObject **result)
649 {
650 	return lookup_object_from_handle (self, handle, FALSE, result);
651 }
652 
653 CK_RV
gkm_session_lookup_writable_object(GkmSession * self,CK_OBJECT_HANDLE handle,GkmObject ** result)654 gkm_session_lookup_writable_object (GkmSession *self, CK_OBJECT_HANDLE handle,
655                                     GkmObject **result)
656 {
657 	return lookup_object_from_handle (self, handle, TRUE, result);
658 }
659 
660 CK_RV
gkm_session_login_context_specific(GkmSession * self,CK_UTF8CHAR_PTR pin,CK_ULONG n_pin)661 gkm_session_login_context_specific (GkmSession *self, CK_UTF8CHAR_PTR pin, CK_ULONG n_pin)
662 {
663 	GkmCredential *cred;
664 	gboolean always_auth;
665 	gboolean is_private;
666 	GkmObject *object;
667 	CK_RV rv;
668 
669 	g_return_val_if_fail (GKM_IS_SESSION (self), CKR_GENERAL_ERROR);
670 
671 	if (!self->pv->current_object)
672 		return CKR_OPERATION_NOT_INITIALIZED;
673 
674 	object = self->pv->current_object;
675 	g_return_val_if_fail (GKM_IS_OBJECT (object), CKR_GENERAL_ERROR);
676 
677 	if (!gkm_object_get_attribute_boolean (object, self, CKA_ALWAYS_AUTHENTICATE, &always_auth))
678 		always_auth = FALSE;
679 	if (!gkm_object_get_attribute_boolean (object, self, CKA_PRIVATE, &is_private))
680 		is_private = FALSE;
681 
682 	/* A strange code, but that's what the spec says */
683 	if (always_auth == FALSE)
684 		return CKR_OPERATION_NOT_INITIALIZED;
685 
686 	/* Double check that the object has what it takes */
687 	g_return_val_if_fail (is_private == TRUE, CKR_GENERAL_ERROR);
688 
689 	/* Now create the strange object */
690 	rv = gkm_credential_create (self->pv->module, self->pv->manager,
691 	                            self->pv->current_object, pin, n_pin, &cred);
692 	if (rv != CKR_OK)
693 		return rv;
694 
695 	if (self->pv->credential)
696 		g_object_unref (self->pv->credential);
697 	g_object_set_data (G_OBJECT (cred), "owned-by-session", self);
698 	self->pv->credential = cred;
699 
700 	return CKR_OK;
701 }
702 
703 void
gkm_session_add_session_object(GkmSession * self,GkmTransaction * transaction,GkmObject * obj)704 gkm_session_add_session_object (GkmSession *self, GkmTransaction *transaction,
705                                 GkmObject *obj)
706 {
707 	g_return_if_fail (GKM_IS_SESSION (self));
708 	g_return_if_fail (gkm_session_for_session_object (obj) == NULL);
709 
710 	if (transaction) {
711 		g_return_if_fail (GKM_IS_TRANSACTION (transaction));
712 		g_return_if_fail (!gkm_transaction_get_failed (transaction));
713 	}
714 
715 	add_object (self, transaction, obj);
716 }
717 
718 void
gkm_session_destroy_session_object(GkmSession * self,GkmTransaction * transaction,GkmObject * obj)719 gkm_session_destroy_session_object (GkmSession *self, GkmTransaction *transaction,
720                                     GkmObject *obj)
721 {
722 	g_return_if_fail (GKM_IS_SESSION (self));
723 	g_return_if_fail (gkm_session_for_session_object (obj) == self);
724 
725 	if (transaction) {
726 		g_return_if_fail (GKM_IS_TRANSACTION (transaction));
727 		g_return_if_fail (!gkm_transaction_get_failed (transaction));
728 	}
729 
730 	/* Don't actually destroy the credential */
731 	if (self->pv->credential && GKM_OBJECT (self->pv->credential) == obj)
732 		return;
733 
734 	remove_object (self, transaction, obj);
735 }
736 
737 GkmCredential*
gkm_session_get_credential(GkmSession * self)738 gkm_session_get_credential (GkmSession *self)
739 {
740 	g_return_val_if_fail (GKM_IS_SESSION (self), NULL);
741 	return self->pv->credential;
742 }
743 
744 GkmObject*
gkm_session_create_object_for_factory(GkmSession * self,GkmFactory * factory,GkmTransaction * transaction,CK_ATTRIBUTE_PTR template,CK_ULONG count)745 gkm_session_create_object_for_factory (GkmSession *self, GkmFactory *factory,
746                                        GkmTransaction *transaction,
747                                        CK_ATTRIBUTE_PTR template, CK_ULONG count)
748 {
749 	GkmTransaction *owned = NULL;
750 	GkmObject  *object;
751 	gboolean token;
752 
753 	g_return_val_if_fail (GKM_IS_SESSION (self), NULL);
754 	g_return_val_if_fail (factory && factory->func, NULL);
755 	g_return_val_if_fail (template || !count, NULL);
756 
757 	/* The transaction for this whole dealio */
758 	if (!transaction)
759 		owned = transaction = gkm_transaction_new ();
760 
761 	g_return_val_if_fail (GKM_IS_TRANSACTION (transaction), NULL);
762 
763 	/* Refresh the module if storing on the token */
764 	if (gkm_attributes_find_boolean (template, count, CKA_TOKEN, &token) && token)
765 		gkm_module_refresh_token (self->pv->module);
766 
767 	/*
768 	 * Duplicate the memory for the attributes (but not values) so we
769 	 * can 'consume' in the factory function
770 	 */
771 	template = g_memdup (template, count * sizeof (CK_ATTRIBUTE));
772 
773 	/* Actually create the object */
774 	object = (factory->func) (self, transaction, template, count);
775 
776 	/* A NULL result without a failure code, bad */
777 	if (object == NULL && !gkm_transaction_get_failed (transaction)) {
778 		g_warn_if_reached ();
779 		gkm_transaction_fail (transaction, CKR_GENERAL_ERROR);
780 	}
781 
782 	g_free (template);
783 
784 	if (owned)
785 		gkm_transaction_complete (transaction);
786 
787 	/* Object is owned by module or session */
788 	if (gkm_transaction_get_failed (transaction)) {
789 		if (object)
790 			g_object_unref (object);
791 		object = NULL;
792 	}
793 
794 	if (owned)
795 		g_object_unref (owned);
796 
797 	return object;
798 }
799 
800 GkmObject*
gkm_session_create_object_for_attributes(GkmSession * self,GkmTransaction * transaction,CK_ATTRIBUTE_PTR attrs,CK_ULONG n_attrs)801 gkm_session_create_object_for_attributes (GkmSession *self, GkmTransaction *transaction,
802                                           CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
803 {
804 	GkmFactory *factory;
805 
806 	g_return_val_if_fail (GKM_IS_SESSION (self), NULL);
807 
808 	/* Find out if we can create such an object */
809 	factory = gkm_module_find_factory (gkm_session_get_module (self), attrs, n_attrs);
810 	if (factory == NULL) {
811 		if (transaction)
812 			gkm_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
813 		return NULL;
814 	}
815 
816 	return gkm_session_create_object_for_factory (self, factory, transaction, attrs, n_attrs);
817 }
818 
819 void
gkm_session_complete_object_creation(GkmSession * self,GkmTransaction * transaction,GkmObject * object,gboolean add,CK_ATTRIBUTE_PTR attrs,CK_ULONG n_attrs)820 gkm_session_complete_object_creation (GkmSession *self, GkmTransaction *transaction, GkmObject *object,
821                                       gboolean add, CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
822 {
823 	gboolean is_private;
824 	gulong i;
825 
826 	g_return_if_fail (GKM_IS_SESSION (self));
827 	g_return_if_fail (GKM_IS_OBJECT (object));
828 	g_return_if_fail (GKM_IS_TRANSACTION (transaction));
829 	g_return_if_fail (!gkm_transaction_get_failed (transaction));
830 
831 	gkm_object_create_attributes (object, self, transaction, attrs, n_attrs);
832 	if (gkm_transaction_get_failed (transaction))
833 		return;
834 
835 	/* See if we can create due to read-only */
836 	if (gkm_object_is_token (object)) {
837 		if (!gkm_object_is_transient (object) &&
838 		    gkm_module_get_write_protected (self->pv->module)) {
839 			gkm_transaction_fail (transaction, CKR_TOKEN_WRITE_PROTECTED);
840 			return;
841 		}
842 		else if (gkm_session_is_read_only (self)) {
843 			gkm_transaction_fail (transaction, CKR_SESSION_READ_ONLY);
844 			return;
845 		}
846 	}
847 
848 	/* Can only create public objects unless logged in */
849 	if (gkm_session_get_logged_in (self) != CKU_USER &&
850 	    gkm_object_get_attribute_boolean (object, self, CKA_PRIVATE, &is_private) &&
851 	    is_private == TRUE) {
852 		gkm_transaction_fail (transaction, CKR_USER_NOT_LOGGED_IN);
853 		return;
854 	}
855 
856 	/* Add the object to session or token */
857 	if (add && !gkm_transaction_get_failed (transaction)) {
858 		if (gkm_object_is_token (object))
859 			gkm_module_add_token_object (self->pv->module, transaction, object);
860 		else
861 			add_object (self, transaction, object);
862 	}
863 
864 	/* Next go through and set all attributes that weren't used initially */
865 	gkm_attributes_consume (attrs, n_attrs, CKA_TOKEN, G_MAXULONG);
866 	for (i = 0; i < n_attrs && !gkm_transaction_get_failed (transaction); ++i) {
867 		if (!gkm_attribute_consumed (&attrs[i]))
868 			gkm_object_set_attribute (object, self, transaction, &attrs[i]);
869 	}
870 
871 	/* Store the object */
872 	if (!gkm_transaction_get_failed (transaction)) {
873 		if (gkm_object_is_token (object))
874 			gkm_module_store_token_object (self->pv->module, transaction, object);
875 	}
876 }
877 
878 /* -----------------------------------------------------------------------------
879  * PKCS#11
880  */
881 
882 CK_RV
gkm_session_C_GetFunctionStatus(GkmSession * self)883 gkm_session_C_GetFunctionStatus (GkmSession *self)
884 {
885 	g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
886 	return CKR_FUNCTION_NOT_PARALLEL;
887 }
888 
889 CK_RV
gkm_session_C_CancelFunction(GkmSession * self)890 gkm_session_C_CancelFunction (GkmSession *self)
891 {
892 	g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
893 	return CKR_FUNCTION_NOT_PARALLEL;
894 }
895 
896 CK_RV
gkm_session_C_GetSessionInfo(GkmSession * self,CK_SESSION_INFO_PTR info)897 gkm_session_C_GetSessionInfo(GkmSession* self, CK_SESSION_INFO_PTR info)
898 {
899 	g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
900 	if (!info)
901 		return CKR_ARGUMENTS_BAD;
902 
903 	info->slotID = self->pv->slot_id;
904 	if (self->pv->logged_in == CKU_USER)
905 		info->state = gkm_session_is_read_only (self) ? CKS_RO_USER_FUNCTIONS : CKS_RW_USER_FUNCTIONS;
906 	else if (self->pv->logged_in == CKU_SO)
907 		info->state = CKS_RW_SO_FUNCTIONS;
908 	else
909 		info->state = gkm_session_is_read_only (self) ? CKS_RO_PUBLIC_SESSION : CKS_RW_PUBLIC_SESSION;
910 	info->flags = CKF_SERIAL_SESSION | self->pv->flags;
911 	info->ulDeviceError = 0;
912 
913 	return CKR_OK;
914 }
915 
916 CK_RV
gkm_session_C_GetOperationState(GkmSession * self,CK_BYTE_PTR operation_state,CK_ULONG_PTR operation_state_len)917 gkm_session_C_GetOperationState (GkmSession* self, CK_BYTE_PTR operation_state,
918                                  CK_ULONG_PTR operation_state_len)
919 {
920 	/* Nope, We don't bend that way */
921 	return CKR_FUNCTION_NOT_SUPPORTED;
922 }
923 
924 CK_RV
gkm_session_C_SetOperationState(GkmSession * self,CK_BYTE_PTR operation_state,CK_ULONG operation_state_len,CK_OBJECT_HANDLE encryption_key,CK_OBJECT_HANDLE authentication_key)925 gkm_session_C_SetOperationState (GkmSession* self, CK_BYTE_PTR operation_state,
926                                  CK_ULONG operation_state_len, CK_OBJECT_HANDLE encryption_key,
927                                  CK_OBJECT_HANDLE authentication_key)
928 {
929 	/* Nope. We don't bend that way */
930 	return CKR_FUNCTION_NOT_SUPPORTED;
931 }
932 
933 CK_RV
gkm_session_C_CreateObject(GkmSession * self,CK_ATTRIBUTE_PTR template,CK_ULONG count,CK_OBJECT_HANDLE_PTR new_object)934 gkm_session_C_CreateObject (GkmSession* self, CK_ATTRIBUTE_PTR template,
935                             CK_ULONG count, CK_OBJECT_HANDLE_PTR new_object)
936 {
937 	GkmObject *object = NULL;
938 	CK_OBJECT_HANDLE handle;
939 	GkmTransaction *transaction;
940 	CK_RV rv;
941 
942 	g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
943 	if (!new_object)
944 		return CKR_ARGUMENTS_BAD;
945 	if (!(!count || template))
946 		return CKR_ARGUMENTS_BAD;
947 
948 	transaction = gkm_transaction_new ();
949 
950 	object = gkm_session_create_object_for_attributes (self, transaction, template, count);
951 
952 	rv = gkm_transaction_complete_and_unref (transaction);
953 
954 	if (rv == CKR_OK) {
955 		g_assert (object);
956 		handle = gkm_object_get_handle (object);
957 		if (handle == 0) {
958 			g_warning ("an object was not properly exposed its owner");
959 			rv = CKR_GENERAL_ERROR;
960 		} else {
961 			*new_object = handle;
962 		}
963 		g_object_unref (object);
964 	}
965 
966 	return rv;
967 }
968 
969 CK_RV
gkm_session_C_CopyObject(GkmSession * self,CK_OBJECT_HANDLE object,CK_ATTRIBUTE_PTR template,CK_ULONG count,CK_OBJECT_HANDLE_PTR new_object)970 gkm_session_C_CopyObject (GkmSession* self, CK_OBJECT_HANDLE object,
971                           CK_ATTRIBUTE_PTR template, CK_ULONG count,
972                           CK_OBJECT_HANDLE_PTR new_object)
973 {
974 	/*
975 	 * TODO: We need to implement this, initially perhaps only
976 	 * only for session objects.
977 	 */
978 	return CKR_FUNCTION_NOT_SUPPORTED;
979 }
980 
981 CK_RV
gkm_session_C_GetObjectSize(GkmSession * self,CK_OBJECT_HANDLE object,CK_ULONG_PTR size)982 gkm_session_C_GetObjectSize (GkmSession* self, CK_OBJECT_HANDLE object, CK_ULONG_PTR size)
983 {
984 	/* TODO: Do we need to implement this? */
985 	return CKR_FUNCTION_NOT_SUPPORTED;
986 }
987 
988 CK_RV
gkm_session_C_GetAttributeValue(GkmSession * self,CK_OBJECT_HANDLE handle,CK_ATTRIBUTE_PTR template,CK_ULONG count)989 gkm_session_C_GetAttributeValue (GkmSession* self, CK_OBJECT_HANDLE handle,
990                                  CK_ATTRIBUTE_PTR template, CK_ULONG count)
991 {
992 	GkmObject *object;
993 	CK_ULONG i;
994 	CK_RV code, rv;
995 
996 	g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
997 	if (!(!count || template))
998 		return CKR_ARGUMENTS_BAD;
999 
1000 	rv = gkm_session_lookup_readable_object (self, handle, &object);
1001 	if (rv != CKR_OK)
1002 		return rv;
1003 
1004 	rv = CKR_OK;
1005 
1006 	for (i = 0; i < count; ++i) {
1007 		code = gkm_object_get_attribute (object, self, &template[i]);
1008 
1009 		/* Not a true error, keep going */
1010 		if (code == CKR_ATTRIBUTE_SENSITIVE ||
1011 		    code == CKR_ATTRIBUTE_TYPE_INVALID) {
1012 			template[i].ulValueLen = (CK_ULONG)-1;
1013 			rv = code;
1014 
1015 		} else if(code == CKR_BUFFER_TOO_SMALL) {
1016 			rv = code;
1017 
1018 		/* Any other error aborts */
1019 		} else if (code != CKR_OK) {
1020 			rv = code;
1021 			break;
1022 		}
1023 	}
1024 
1025 	return rv;
1026 }
1027 
1028 CK_RV
gkm_session_C_SetAttributeValue(GkmSession * self,CK_OBJECT_HANDLE handle,CK_ATTRIBUTE_PTR template,CK_ULONG count)1029 gkm_session_C_SetAttributeValue (GkmSession* self, CK_OBJECT_HANDLE handle,
1030                                  CK_ATTRIBUTE_PTR template, CK_ULONG count)
1031 {
1032 	GkmObject *object = NULL;
1033 	GkmTransaction *transaction;
1034 	CK_ULONG i;
1035 	CK_RV rv;
1036 
1037 	g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1038 	if (!(!count || template))
1039 		return CKR_ARGUMENTS_BAD;
1040 
1041 	rv = gkm_session_lookup_writable_object (self, handle, &object);
1042 	if (rv != CKR_OK)
1043 		return rv;
1044 
1045 	/* The transaction for this whole dealio */
1046 	transaction = gkm_transaction_new ();
1047 
1048 	for (i = 0; i < count && !gkm_transaction_get_failed (transaction); ++i)
1049 		gkm_object_set_attribute (object, self, transaction, &template[i]);
1050 
1051 	/* Store the object */
1052 	if (!gkm_transaction_get_failed (transaction) && gkm_object_is_token (object))
1053 		gkm_module_store_token_object (self->pv->module, transaction, object);
1054 
1055 	gkm_transaction_complete (transaction);
1056 	rv = gkm_transaction_get_result (transaction);
1057 	g_object_unref (transaction);
1058 
1059 	return rv;
1060 }
1061 
1062 CK_RV
gkm_session_C_DestroyObject(GkmSession * self,CK_OBJECT_HANDLE handle)1063 gkm_session_C_DestroyObject (GkmSession* self, CK_OBJECT_HANDLE handle)
1064 {
1065 	GkmObject *object;
1066 	GkmSession *session;
1067 	GkmTransaction *transaction;
1068 	CK_RV rv;
1069 
1070 	g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1071 
1072 	rv = gkm_session_lookup_writable_object (self, handle, &object);
1073 	if (rv != CKR_OK)
1074 		return rv;
1075 
1076 	transaction = gkm_transaction_new ();
1077 
1078 	/* Lookup the actual session that owns this object, if no session, then a token object */
1079 	session = gkm_session_for_session_object (object);
1080 	if (session != NULL)
1081 		remove_object (session, transaction, object);
1082 	else
1083 		gkm_module_remove_token_object (self->pv->module, transaction, object);
1084 
1085 	gkm_transaction_complete (transaction);
1086 	rv = gkm_transaction_get_result (transaction);
1087 	g_object_unref (transaction);
1088 
1089 	if (rv == CKR_OK) {
1090 		/* Check that it's really gone */
1091 		g_return_val_if_fail (gkm_session_lookup_readable_object (self, handle, &object) ==
1092 		                      CKR_OBJECT_HANDLE_INVALID, CKR_GENERAL_ERROR);
1093 	}
1094 
1095 	return rv;
1096 }
1097 
1098 CK_RV
gkm_session_C_FindObjectsInit(GkmSession * self,CK_ATTRIBUTE_PTR template,CK_ULONG count)1099 gkm_session_C_FindObjectsInit (GkmSession* self, CK_ATTRIBUTE_PTR template,
1100                                CK_ULONG count)
1101 {
1102 	gboolean token = FALSE;
1103 	gboolean also_private;
1104 	CK_RV rv = CKR_OK;
1105 	GArray *found;
1106 	gboolean all;
1107 
1108 	g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1109 	if (!(template || !count))
1110 		return CKR_ARGUMENTS_BAD;
1111 
1112 	/* Cancel any current operation */
1113 	if (self->pv->current_operation) {
1114 		(self->pv->current_operation) (self);
1115 		g_assert (!self->pv->current_operation);
1116 	}
1117 
1118 	/* See whether this is token or not */
1119 	all = !gkm_attributes_find_boolean (template, count, CKA_TOKEN, &token);
1120 
1121 	/* An array of object handles */
1122 	found = g_array_new (FALSE, TRUE, sizeof (CK_OBJECT_HANDLE));
1123 
1124 	/* If not logged in, then skip private objects */
1125 	also_private = gkm_session_get_logged_in (self) == CKU_USER;
1126 
1127 	if (all || token) {
1128 		rv = gkm_module_refresh_token (self->pv->module);
1129 		if (rv == CKR_OK)
1130 			rv = gkm_manager_find_handles (gkm_module_get_manager (self->pv->module),
1131 			                               self, also_private, template, count, found);
1132 	}
1133 
1134 	if (rv == CKR_OK && (all || !token)) {
1135 		rv = gkm_manager_find_handles (self->pv->manager, self, also_private,
1136 		                               template, count, found);
1137 	}
1138 
1139 	if (rv != CKR_OK) {
1140 		g_array_free (found, TRUE);
1141 		return rv;
1142 	}
1143 
1144 	g_assert (!self->pv->current_operation);
1145 	g_assert (!self->pv->found_objects);
1146 
1147 	self->pv->found_objects = found;
1148 	self->pv->current_operation = cleanup_found;
1149 
1150 	return CKR_OK;
1151 }
1152 
1153 CK_RV
gkm_session_C_FindObjects(GkmSession * self,CK_OBJECT_HANDLE_PTR objects,CK_ULONG max_count,CK_ULONG_PTR count)1154 gkm_session_C_FindObjects (GkmSession* self, CK_OBJECT_HANDLE_PTR objects,
1155                            CK_ULONG max_count, CK_ULONG_PTR count)
1156 {
1157 	CK_ULONG n_objects, i;
1158 	GArray *found;
1159 
1160 	g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1161 	if (!(objects || !max_count))
1162 		return CKR_ARGUMENTS_BAD;
1163 	if (!count)
1164 		return CKR_ARGUMENTS_BAD;
1165 
1166 	if (self->pv->current_operation != cleanup_found)
1167 		return CKR_OPERATION_NOT_INITIALIZED;
1168 
1169 	g_assert (self->pv->found_objects);
1170 	found = self->pv->found_objects;
1171 
1172 	n_objects = MIN (max_count, found->len);
1173 	if (n_objects > 0) {
1174 		for (i = 0; i < n_objects; ++i)
1175 			objects[i] = g_array_index (found, CK_OBJECT_HANDLE, i);
1176 		g_array_remove_range (found, 0, n_objects);
1177 	}
1178 
1179 	*count = n_objects;
1180 	return CKR_OK;
1181 
1182 }
1183 
1184 CK_RV
gkm_session_C_FindObjectsFinal(GkmSession * self)1185 gkm_session_C_FindObjectsFinal (GkmSession* self)
1186 {
1187 	g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1188 
1189 	if (self->pv->current_operation != cleanup_found)
1190 		return CKR_OPERATION_NOT_INITIALIZED;
1191 
1192 	cleanup_found (self);
1193 	return CKR_OK;
1194 }
1195 
1196 CK_RV
gkm_session_C_EncryptInit(GkmSession * self,CK_MECHANISM_PTR mechanism,CK_OBJECT_HANDLE key)1197 gkm_session_C_EncryptInit (GkmSession *self, CK_MECHANISM_PTR mechanism,
1198                            CK_OBJECT_HANDLE key)
1199 {
1200 	g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1201 	if (!mechanism)
1202 		return CKR_ARGUMENTS_BAD;
1203 	return prepare_crypto (self, mechanism, CKA_ENCRYPT, key);
1204 }
1205 
1206 CK_RV
gkm_session_C_Encrypt(GkmSession * self,CK_BYTE_PTR data,CK_ULONG data_len,CK_BYTE_PTR encrypted_data,CK_ULONG_PTR encrypted_data_len)1207 gkm_session_C_Encrypt (GkmSession *self, CK_BYTE_PTR data, CK_ULONG data_len,
1208                        CK_BYTE_PTR encrypted_data, CK_ULONG_PTR encrypted_data_len)
1209 {
1210 	g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1211 	return process_crypto (self, CKA_ENCRYPT, data, data_len, encrypted_data, encrypted_data_len);
1212 }
1213 
1214 CK_RV
gkm_session_C_EncryptUpdate(GkmSession * self,CK_BYTE_PTR part,CK_ULONG part_len,CK_BYTE_PTR encrypted_part,CK_ULONG_PTR encrypted_part_len)1215 gkm_session_C_EncryptUpdate (GkmSession *self, CK_BYTE_PTR part,
1216                              CK_ULONG part_len, CK_BYTE_PTR encrypted_part,
1217                              CK_ULONG_PTR encrypted_part_len)
1218 {
1219 	/* Our keys don't support this incremental encryption */
1220 	return CKR_FUNCTION_NOT_SUPPORTED;
1221 }
1222 
1223 CK_RV
gkm_session_C_EncryptFinal(GkmSession * self,CK_BYTE_PTR last_part,CK_ULONG_PTR last_part_len)1224 gkm_session_C_EncryptFinal (GkmSession *self, CK_BYTE_PTR last_part,
1225                             CK_ULONG_PTR last_part_len)
1226 {
1227 	/* Our keys don't support this incremental encryption */
1228 	return CKR_FUNCTION_NOT_SUPPORTED;
1229 }
1230 
1231 CK_RV
gkm_session_C_DecryptInit(GkmSession * self,CK_MECHANISM_PTR mechanism,CK_OBJECT_HANDLE key)1232 gkm_session_C_DecryptInit (GkmSession *self, CK_MECHANISM_PTR mechanism,
1233                            CK_OBJECT_HANDLE key)
1234 {
1235 	g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1236 	if (!mechanism)
1237 		return CKR_ARGUMENTS_BAD;
1238 	return prepare_crypto (self, mechanism, CKA_DECRYPT, key);
1239 }
1240 
1241 CK_RV
gkm_session_C_Decrypt(GkmSession * self,CK_BYTE_PTR enc_data,CK_ULONG enc_data_len,CK_BYTE_PTR data,CK_ULONG_PTR data_len)1242 gkm_session_C_Decrypt (GkmSession *self, CK_BYTE_PTR enc_data,
1243                        CK_ULONG enc_data_len, CK_BYTE_PTR data, CK_ULONG_PTR data_len)
1244 {
1245 	g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1246 	return process_crypto (self, CKA_DECRYPT, enc_data, enc_data_len, data, data_len);
1247 }
1248 
1249 CK_RV
gkm_session_C_DecryptUpdate(GkmSession * self,CK_BYTE_PTR enc_part,CK_ULONG enc_part_len,CK_BYTE_PTR part,CK_ULONG_PTR part_len)1250 gkm_session_C_DecryptUpdate (GkmSession *self, CK_BYTE_PTR enc_part,
1251                              CK_ULONG enc_part_len, CK_BYTE_PTR part, CK_ULONG_PTR part_len)
1252 {
1253 	/* Our keys don't support this incremental decryption */
1254 	return CKR_FUNCTION_NOT_SUPPORTED;
1255 }
1256 
1257 CK_RV
gkm_session_C_DecryptFinal(GkmSession * self,CK_BYTE_PTR last_part,CK_ULONG_PTR last_part_len)1258 gkm_session_C_DecryptFinal (GkmSession *self, CK_BYTE_PTR last_part,
1259                             CK_ULONG_PTR last_part_len)
1260 {
1261 	/* Our keys don't support this incremental decryption */
1262 	return CKR_FUNCTION_NOT_SUPPORTED;
1263 }
1264 
1265 CK_RV
gkm_session_C_DigestInit(GkmSession * self,CK_MECHANISM_PTR mechanism)1266 gkm_session_C_DigestInit (GkmSession *self, CK_MECHANISM_PTR mechanism)
1267 {
1268 	/* We don't do digests */
1269 	return CKR_FUNCTION_NOT_SUPPORTED;
1270 }
1271 
1272 CK_RV
gkm_session_C_Digest(GkmSession * self,CK_BYTE_PTR data,CK_ULONG data_len,CK_BYTE_PTR digest,CK_ULONG_PTR digest_len)1273 gkm_session_C_Digest (GkmSession *self, CK_BYTE_PTR data, CK_ULONG data_len,
1274                       CK_BYTE_PTR digest, CK_ULONG_PTR digest_len)
1275 {
1276 	/* We don't do digests */
1277 	return CKR_FUNCTION_NOT_SUPPORTED;
1278 }
1279 
1280 CK_RV
gkm_session_C_DigestUpdate(GkmSession * self,CK_BYTE_PTR part,CK_ULONG part_len)1281 gkm_session_C_DigestUpdate (GkmSession *self, CK_BYTE_PTR part, CK_ULONG part_len)
1282 {
1283 	/* We don't do digests */
1284 	return CKR_FUNCTION_NOT_SUPPORTED;
1285 }
1286 
1287 CK_RV
gkm_session_C_DigestKey(GkmSession * self,CK_OBJECT_HANDLE key)1288 gkm_session_C_DigestKey (GkmSession *self, CK_OBJECT_HANDLE key)
1289 {
1290 	/* We don't do digests */
1291 	return CKR_FUNCTION_NOT_SUPPORTED;
1292 }
1293 
1294 CK_RV
gkm_session_C_DigestFinal(GkmSession * self,CK_BYTE_PTR digest,CK_ULONG_PTR digest_len)1295 gkm_session_C_DigestFinal (GkmSession *self, CK_BYTE_PTR digest,
1296                            CK_ULONG_PTR digest_len)
1297 {
1298 	/* We don't do digests */
1299 	return CKR_FUNCTION_NOT_SUPPORTED;
1300 }
1301 
1302 CK_RV
gkm_session_C_SignInit(GkmSession * self,CK_MECHANISM_PTR mechanism,CK_OBJECT_HANDLE key)1303 gkm_session_C_SignInit (GkmSession *self, CK_MECHANISM_PTR mechanism,
1304                         CK_OBJECT_HANDLE key)
1305 {
1306 	g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1307 	if (!mechanism)
1308 		return CKR_ARGUMENTS_BAD;
1309 	return prepare_crypto (self, mechanism, CKA_SIGN, key);
1310 }
1311 
1312 CK_RV
gkm_session_C_Sign(GkmSession * self,CK_BYTE_PTR data,CK_ULONG data_len,CK_BYTE_PTR signature,CK_ULONG_PTR signature_len)1313 gkm_session_C_Sign (GkmSession *self, CK_BYTE_PTR data, CK_ULONG data_len,
1314                     CK_BYTE_PTR signature, CK_ULONG_PTR signature_len)
1315 {
1316 	g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1317 	return process_crypto (self, CKA_SIGN, data, data_len, signature, signature_len);
1318 }
1319 
1320 CK_RV
gkm_session_C_SignUpdate(GkmSession * self,CK_BYTE_PTR part,CK_ULONG part_len)1321 gkm_session_C_SignUpdate (GkmSession *self, CK_BYTE_PTR part, CK_ULONG part_len)
1322 {
1323 	/* Our keys don't support incremental operations */
1324 	return CKR_FUNCTION_NOT_SUPPORTED;
1325 }
1326 
1327 CK_RV
gkm_session_C_SignFinal(GkmSession * self,CK_BYTE_PTR signature,CK_ULONG_PTR signature_len)1328 gkm_session_C_SignFinal (GkmSession *self, CK_BYTE_PTR signature,
1329                          CK_ULONG_PTR signature_len)
1330 {
1331 	/* Our keys don't support incremental operations */
1332 	return CKR_FUNCTION_NOT_SUPPORTED;
1333 }
1334 
1335 CK_RV
gkm_session_C_SignRecoverInit(GkmSession * self,CK_MECHANISM_PTR mechanism,CK_OBJECT_HANDLE key)1336 gkm_session_C_SignRecoverInit (GkmSession *self, CK_MECHANISM_PTR mechanism,
1337                                CK_OBJECT_HANDLE key)
1338 {
1339 	/* TODO: Need to implement */
1340 	return CKR_FUNCTION_NOT_SUPPORTED;
1341 }
1342 
1343 CK_RV
gkm_session_C_SignRecover(GkmSession * self,CK_BYTE_PTR data,CK_ULONG data_len,CK_BYTE_PTR signature,CK_ULONG_PTR signature_len)1344 gkm_session_C_SignRecover (GkmSession *self, CK_BYTE_PTR data, CK_ULONG data_len,
1345                            CK_BYTE_PTR signature, CK_ULONG_PTR signature_len)
1346 {
1347 	/* TODO: Need to implement */
1348 	return CKR_FUNCTION_NOT_SUPPORTED;
1349 }
1350 
1351 CK_RV
gkm_session_C_VerifyInit(GkmSession * self,CK_MECHANISM_PTR mechanism,CK_OBJECT_HANDLE key)1352 gkm_session_C_VerifyInit (GkmSession *self, CK_MECHANISM_PTR mechanism,
1353                           CK_OBJECT_HANDLE key)
1354 {
1355 	g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1356 	if (!mechanism)
1357 		return CKR_ARGUMENTS_BAD;
1358 	return prepare_crypto (self, mechanism, CKA_VERIFY, key);
1359 }
1360 
1361 CK_RV
gkm_session_C_Verify(GkmSession * self,CK_BYTE_PTR data,CK_ULONG data_len,CK_BYTE_PTR signature,CK_ULONG signature_len)1362 gkm_session_C_Verify (GkmSession *self, CK_BYTE_PTR data, CK_ULONG data_len,
1363                       CK_BYTE_PTR signature, CK_ULONG signature_len)
1364 {
1365 	g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1366 	return process_crypto (self, CKA_VERIFY, data, data_len, signature, &signature_len);
1367 }
1368 
1369 CK_RV
gkm_session_C_VerifyUpdate(GkmSession * self,CK_BYTE_PTR part,CK_ULONG part_len)1370 gkm_session_C_VerifyUpdate (GkmSession *self, CK_BYTE_PTR part, CK_ULONG part_len)
1371 {
1372 	/* Our keys don't support incremental operations */
1373 	return CKR_FUNCTION_NOT_SUPPORTED;
1374 }
1375 
1376 CK_RV
gkm_session_C_VerifyFinal(GkmSession * self,CK_BYTE_PTR signature,CK_ULONG signature_len)1377 gkm_session_C_VerifyFinal (GkmSession *self, CK_BYTE_PTR signature,
1378                            CK_ULONG signature_len)
1379 {
1380 	/* Our keys don't support incremental operations */
1381 	return CKR_FUNCTION_NOT_SUPPORTED;
1382 }
1383 
1384 CK_RV
gkm_session_C_VerifyRecoverInit(GkmSession * self,CK_MECHANISM_PTR mechanism,CK_OBJECT_HANDLE key)1385 gkm_session_C_VerifyRecoverInit (GkmSession *self, CK_MECHANISM_PTR mechanism,
1386                                  CK_OBJECT_HANDLE key)
1387 {
1388 	/* TODO: Need to implement */
1389 	return CKR_FUNCTION_NOT_SUPPORTED;
1390 }
1391 
1392 CK_RV
gkm_session_C_VerifyRecover(GkmSession * self,CK_BYTE_PTR signature,CK_ULONG signature_len,CK_BYTE_PTR data,CK_ULONG_PTR data_len)1393 gkm_session_C_VerifyRecover (GkmSession *self, CK_BYTE_PTR signature,
1394                              CK_ULONG signature_len, CK_BYTE_PTR data,
1395                              CK_ULONG_PTR data_len)
1396 {
1397 	/* TODO: Need to implement */
1398 	return CKR_FUNCTION_NOT_SUPPORTED;
1399 }
1400 
1401 CK_RV
gkm_session_C_DigestEncryptUpdate(GkmSession * self,CK_BYTE_PTR part,CK_ULONG part_len,CK_BYTE_PTR enc_part,CK_ULONG_PTR enc_part_len)1402 gkm_session_C_DigestEncryptUpdate (GkmSession *self, CK_BYTE_PTR part,
1403                                    CK_ULONG part_len, CK_BYTE_PTR enc_part,
1404                                    CK_ULONG_PTR enc_part_len)
1405 {
1406 	/* We don't support double operations */
1407 	return CKR_FUNCTION_NOT_SUPPORTED;
1408 }
1409 
1410 CK_RV
gkm_session_C_DecryptDigestUpdate(GkmSession * self,CK_BYTE_PTR enc_part,CK_ULONG enc_part_len,CK_BYTE_PTR part,CK_ULONG_PTR part_len)1411 gkm_session_C_DecryptDigestUpdate (GkmSession *self, CK_BYTE_PTR enc_part,
1412                                    CK_ULONG enc_part_len, CK_BYTE_PTR part,
1413                                    CK_ULONG_PTR part_len)
1414 {
1415 	/* We don't support double operations */
1416 	return CKR_FUNCTION_NOT_SUPPORTED;
1417 }
1418 
1419 CK_RV
gkm_session_C_SignEncryptUpdate(GkmSession * self,CK_BYTE_PTR part,CK_ULONG part_len,CK_BYTE_PTR enc_part,CK_ULONG_PTR enc_part_len)1420 gkm_session_C_SignEncryptUpdate (GkmSession *self, CK_BYTE_PTR part,
1421                                  CK_ULONG part_len, CK_BYTE_PTR enc_part,
1422 				 CK_ULONG_PTR enc_part_len)
1423 {
1424 	/* We don't support double operations */
1425 	return CKR_FUNCTION_NOT_SUPPORTED;
1426 }
1427 
1428 CK_RV
gkm_session_C_DecryptVerifyUpdate(GkmSession * self,CK_BYTE_PTR enc_part,CK_ULONG enc_part_len,CK_BYTE_PTR part,CK_ULONG_PTR part_len)1429 gkm_session_C_DecryptVerifyUpdate (GkmSession *self, CK_BYTE_PTR enc_part,
1430                                    CK_ULONG enc_part_len, CK_BYTE_PTR part,
1431                                    CK_ULONG_PTR part_len)
1432 {
1433 	/* We don't support double operations */
1434 	return CKR_FUNCTION_NOT_SUPPORTED;
1435 }
1436 
1437 CK_RV
gkm_session_C_GenerateKey(GkmSession * self,CK_MECHANISM_PTR mechanism,CK_ATTRIBUTE_PTR template,CK_ULONG count,CK_OBJECT_HANDLE_PTR key)1438 gkm_session_C_GenerateKey (GkmSession* self, CK_MECHANISM_PTR mechanism,
1439                            CK_ATTRIBUTE_PTR template, CK_ULONG count,
1440                            CK_OBJECT_HANDLE_PTR key)
1441 {
1442 	/* TODO: We need to implement this */
1443 	return CKR_FUNCTION_NOT_SUPPORTED;
1444 }
1445 
1446 CK_RV
gkm_session_C_GenerateKeyPair(GkmSession * self,CK_MECHANISM_PTR mechanism,CK_ATTRIBUTE_PTR pub_template,CK_ULONG pub_count,CK_ATTRIBUTE_PTR priv_template,CK_ULONG priv_count,CK_OBJECT_HANDLE_PTR pub_key,CK_OBJECT_HANDLE_PTR priv_key)1447 gkm_session_C_GenerateKeyPair (GkmSession* self, CK_MECHANISM_PTR mechanism,
1448                                CK_ATTRIBUTE_PTR pub_template, CK_ULONG pub_count,
1449                                CK_ATTRIBUTE_PTR priv_template, CK_ULONG priv_count,
1450                                CK_OBJECT_HANDLE_PTR pub_key, CK_OBJECT_HANDLE_PTR priv_key)
1451 {
1452 	GkmObject *pub = NULL;
1453 	GkmObject *priv = NULL;
1454 	GkmTransaction *transaction;
1455 	CK_RV rv;
1456 
1457 	g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1458 	if (!mechanism)
1459 		return CKR_ARGUMENTS_BAD;
1460 	if (!(!pub_count || pub_template))
1461 		return CKR_ARGUMENTS_BAD;
1462 	if (!(!priv_count || priv_template))
1463 		return CKR_ARGUMENTS_BAD;
1464 	if (!pub_key || !priv_key)
1465 		return CKR_ARGUMENTS_BAD;
1466 
1467 	/*
1468 	 * Duplicate the memory for the attributes (but not values) so we
1469 	 * can 'consume' in the generator and create object functions.
1470 	 */
1471 	pub_template = g_memdup (pub_template, pub_count * sizeof (CK_ATTRIBUTE));
1472 	priv_template = g_memdup (priv_template, priv_count * sizeof (CK_ATTRIBUTE));
1473 	transaction = gkm_transaction_new ();
1474 
1475 	/* Actually do the object creation */
1476 	rv = gkm_crypto_generate_key_pair (self, mechanism->mechanism, pub_template, pub_count,
1477 	                                   priv_template, priv_count, &pub, &priv);
1478 	if (rv != CKR_OK)
1479 		gkm_transaction_fail (transaction, rv);
1480 
1481 	g_free (pub_template);
1482 	g_free (priv_template);
1483 
1484 	gkm_transaction_complete (transaction);
1485 	rv = gkm_transaction_get_result (transaction);
1486 	g_object_unref (transaction);
1487 
1488 	if (rv == CKR_OK) {
1489 		*pub_key = gkm_object_get_handle (pub);
1490 		*priv_key = gkm_object_get_handle (priv);
1491 	}
1492 
1493 	/* Objects are owned by storage */
1494 	if (pub != NULL)
1495 		g_object_unref (pub);
1496 	if (priv != NULL)
1497 		g_object_unref (priv);
1498 
1499 	return rv;
1500 }
1501 
1502 CK_RV
gkm_session_C_WrapKey(GkmSession * self,CK_MECHANISM_PTR mechanism,CK_OBJECT_HANDLE wrapping_key,CK_OBJECT_HANDLE key,CK_BYTE_PTR wrapped_key,CK_ULONG_PTR wrapped_key_len)1503 gkm_session_C_WrapKey (GkmSession* self, CK_MECHANISM_PTR mechanism,
1504                        CK_OBJECT_HANDLE wrapping_key, CK_OBJECT_HANDLE key,
1505                        CK_BYTE_PTR wrapped_key, CK_ULONG_PTR wrapped_key_len)
1506 {
1507 	GkmObject *wrapper = NULL;
1508 	GkmObject *wrapped = NULL;
1509 	CK_RV rv;
1510 
1511 	g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1512 	if (!mechanism)
1513 		return CKR_ARGUMENTS_BAD;
1514 	if (!wrapped_key_len)
1515 		return CKR_ARGUMENTS_BAD;
1516 
1517 	rv = gkm_session_lookup_readable_object (self, wrapping_key, &wrapper);
1518 	if (rv == CKR_OBJECT_HANDLE_INVALID)
1519 		return CKR_WRAPPING_KEY_HANDLE_INVALID;
1520 	else if (rv != CKR_OK)
1521 		return rv;
1522 
1523 	rv = gkm_session_lookup_readable_object (self, key, &wrapped);
1524 	if (rv == CKR_OBJECT_HANDLE_INVALID)
1525 		return CKR_KEY_HANDLE_INVALID;
1526 	else if (rv != CKR_OK)
1527 		return rv;
1528 
1529 	return gkm_crypto_wrap_key (self, mechanism, wrapper, wrapped,
1530 	                            wrapped_key, wrapped_key_len);
1531 }
1532 
1533 CK_RV
gkm_session_C_UnwrapKey(GkmSession * self,CK_MECHANISM_PTR mechanism,CK_OBJECT_HANDLE unwrapping_key,CK_BYTE_PTR wrapped_key,CK_ULONG wrapped_key_len,CK_ATTRIBUTE_PTR template,CK_ULONG count,CK_OBJECT_HANDLE_PTR key)1534 gkm_session_C_UnwrapKey (GkmSession* self, CK_MECHANISM_PTR mechanism,
1535                          CK_OBJECT_HANDLE unwrapping_key, CK_BYTE_PTR wrapped_key,
1536                          CK_ULONG wrapped_key_len, CK_ATTRIBUTE_PTR template,
1537                          CK_ULONG count, CK_OBJECT_HANDLE_PTR key)
1538 {
1539 	GkmObject *wrapper = NULL;
1540 	GkmObject *unwrapped = NULL;
1541 	CK_RV rv;
1542 
1543 	g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1544 	if (!mechanism)
1545 		return CKR_ARGUMENTS_BAD;
1546 	if (!(!count || template))
1547 		return CKR_ARGUMENTS_BAD;
1548 	if (!key)
1549 		return CKR_ARGUMENTS_BAD;
1550 
1551 	rv = gkm_session_lookup_readable_object (self, unwrapping_key, &wrapper);
1552 	if (rv == CKR_OBJECT_HANDLE_INVALID)
1553 		return CKR_WRAPPING_KEY_HANDLE_INVALID;
1554 	else if (rv != CKR_OK)
1555 		return rv;
1556 
1557 	/*
1558 	 * Duplicate the memory for the attributes (but not values) so we
1559 	 * can 'consume' in the generator and create object functions.
1560 	 */
1561 	template = g_memdup (template, count * sizeof (CK_ATTRIBUTE));
1562 
1563 	rv = gkm_crypto_unwrap_key (self, mechanism, wrapper, wrapped_key,
1564 	                            wrapped_key_len, template, count, &unwrapped);
1565 
1566 	g_free (template);
1567 
1568 	if (rv == CKR_OK) {
1569 		*key = gkm_object_get_handle (unwrapped);
1570 		g_object_unref (unwrapped);
1571 	}
1572 
1573 	return rv;
1574 }
1575 
1576 CK_RV
gkm_session_C_DeriveKey(GkmSession * self,CK_MECHANISM_PTR mechanism,CK_OBJECT_HANDLE base_key,CK_ATTRIBUTE_PTR template,CK_ULONG count,CK_OBJECT_HANDLE_PTR key)1577 gkm_session_C_DeriveKey (GkmSession* self, CK_MECHANISM_PTR mechanism,
1578                          CK_OBJECT_HANDLE base_key, CK_ATTRIBUTE_PTR template,
1579                          CK_ULONG count, CK_OBJECT_HANDLE_PTR key)
1580 {
1581 	GkmObject *base = NULL;
1582 	GkmObject *derived = NULL;
1583 	CK_RV rv;
1584 
1585 	g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1586 	if (!mechanism)
1587 		return CKR_ARGUMENTS_BAD;
1588 	if (!(!count || template))
1589 		return CKR_ARGUMENTS_BAD;
1590 	if (!key)
1591 		return CKR_ARGUMENTS_BAD;
1592 
1593 	rv = gkm_session_lookup_readable_object (self, base_key, &base);
1594 	if (rv != CKR_OK)
1595 		return rv;
1596 
1597 	/*
1598 	 * Duplicate the memory for the attributes (but not values) so we
1599 	 * can 'consume' in the generator and create object functions.
1600 	 */
1601 	template = g_memdup (template, count * sizeof (CK_ATTRIBUTE));
1602 
1603 	/* Actually do the object creation */
1604 	rv = gkm_crypto_derive_key (self, mechanism, base, template, count, &derived);
1605 
1606 	g_free (template);
1607 
1608 	if (rv == CKR_OK) {
1609 		*key = gkm_object_get_handle (derived);
1610 		g_object_unref (derived);
1611 	}
1612 
1613 	return rv;
1614 }
1615 
1616 CK_RV
gkm_session_C_SeedRandom(GkmSession * self,CK_BYTE_PTR seed,CK_ULONG seed_len)1617 gkm_session_C_SeedRandom (GkmSession* self, CK_BYTE_PTR seed, CK_ULONG seed_len)
1618 {
1619 	/* We don't have a RNG */
1620 	return CKR_RANDOM_NO_RNG;
1621 }
1622 
1623 CK_RV
gkm_session_C_GenerateRandom(GkmSession * self,CK_BYTE_PTR random_data,CK_ULONG random_len)1624 gkm_session_C_GenerateRandom (GkmSession* self, CK_BYTE_PTR random_data,
1625                               CK_ULONG random_len)
1626 {
1627 	/* We don't have a RNG */
1628 	return CKR_RANDOM_NO_RNG;
1629 }
1630