1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /* gck-slot.c - the GObject PKCS#11 wrapper library
3 
4    Copyright (C) 2008, Stefan Walter
5 
6    The Gnome Keyring Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    License, or (at your option) any later version.
10 
11    The Gnome Keyring Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15 
16    You should have received a copy of the GNU Library General Public
17    License along with the Gnome Library; see the file COPYING.LIB.  If not,
18    see <http://www.gnu.org/licenses/>.
19 
20    Author: Stef Walter <nielsen@memberwebs.com>
21 */
22 
23 #include "config.h"
24 
25 #include "gck.h"
26 #include "gck-private.h"
27 
28 #include "egg/egg-timegm.h"
29 
30 #include <string.h>
31 #include <time.h>
32 
33 /**
34  * SECTION:gck-slot
35  * @title: GckSlot
36  * @short_description: Represents a PKCS\#11 slot that can contain a token.
37  *
38  * A PKCS11 slot can contain a token. As an example, a slot might be a card reader, and the token
39  * the card. If the PKCS\#11 module is not a hardware driver, often the slot and token are equivalent.
40  */
41 
42 /**
43  * GckSlot:
44  *
45  * Represents a PKCS11 slot.
46  */
47 
48 enum {
49 	PROP_0,
50 	PROP_MODULE,
51 	PROP_HANDLE
52 };
53 
54 struct _GckSlotPrivate {
55 	GckModule *module;
56 	CK_SLOT_ID handle;
57 };
58 
59 G_DEFINE_TYPE_WITH_PRIVATE (GckSlot, gck_slot, G_TYPE_OBJECT);
60 
61 /* ----------------------------------------------------------------------------
62  * OBJECT
63  */
64 
65 static void
gck_slot_init(GckSlot * self)66 gck_slot_init (GckSlot *self)
67 {
68 	self->pv = gck_slot_get_instance_private (self);
69 }
70 
71 static void
gck_slot_get_property(GObject * obj,guint prop_id,GValue * value,GParamSpec * pspec)72 gck_slot_get_property (GObject *obj, guint prop_id, GValue *value,
73                        GParamSpec *pspec)
74 {
75 	GckSlot *self = GCK_SLOT (obj);
76 
77 	switch (prop_id) {
78 	case PROP_MODULE:
79 		g_value_take_object (value, gck_slot_get_module (self));
80 		break;
81 	case PROP_HANDLE:
82 		g_value_set_ulong (value, gck_slot_get_handle (self));
83 		break;
84 	default:
85 		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
86 		break;
87 	}
88 }
89 
90 static void
gck_slot_set_property(GObject * obj,guint prop_id,const GValue * value,GParamSpec * pspec)91 gck_slot_set_property (GObject *obj, guint prop_id, const GValue *value,
92                         GParamSpec *pspec)
93 {
94 	GckSlot *self = GCK_SLOT (obj);
95 
96 	/* All writes to data members below, happen only during construct phase */
97 
98 	switch (prop_id) {
99 	case PROP_MODULE:
100 		g_assert (!self->pv->module);
101 		self->pv->module = g_value_get_object (value);
102 		g_assert (self->pv->module);
103 		g_object_ref (self->pv->module);
104 		break;
105 	case PROP_HANDLE:
106 		g_assert (!self->pv->handle);
107 		self->pv->handle = g_value_get_ulong (value);
108 		break;
109 	default:
110 		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
111 		break;
112 	}
113 }
114 
115 static void
gck_slot_finalize(GObject * obj)116 gck_slot_finalize (GObject *obj)
117 {
118 	GckSlot *self = GCK_SLOT (obj);
119 
120 	g_clear_object (&self->pv->module);
121 
122 	G_OBJECT_CLASS (gck_slot_parent_class)->finalize (obj);
123 }
124 
125 static void
gck_slot_class_init(GckSlotClass * klass)126 gck_slot_class_init (GckSlotClass *klass)
127 {
128 	GObjectClass *gobject_class = (GObjectClass*)klass;
129 	gck_slot_parent_class = g_type_class_peek_parent (klass);
130 
131 	gobject_class->get_property = gck_slot_get_property;
132 	gobject_class->set_property = gck_slot_set_property;
133 	gobject_class->finalize = gck_slot_finalize;
134 
135 	/**
136 	 * GckSlot:module:
137 	 *
138 	 * The PKCS11 object that this slot is a part of.
139 	 */
140 	g_object_class_install_property (gobject_class, PROP_MODULE,
141 		g_param_spec_object ("module", "Module", "PKCS11 Module",
142 		                     GCK_TYPE_MODULE,
143 		                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
144 
145 	/**
146 	 * GckSlot:handle:
147 	 *
148 	 * The raw CK_SLOT_ID handle of this slot.
149 	 */
150 	g_object_class_install_property (gobject_class, PROP_HANDLE,
151 		g_param_spec_ulong ("handle", "Handle", "PKCS11 Slot ID",
152 		                   0, G_MAXULONG, 0,
153 		                   G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
154 }
155 
156 /* ----------------------------------------------------------------------------
157  * PUBLIC
158  */
159 
160 /**
161  * GckSlotInfo:
162  * @slot_description: Description of the slot.
163  * @manufacturer_id: The manufacturer of this slot.
164  * @flags: Various PKCS11 flags that apply to this slot.
165  * @hardware_version_major: The major version of the hardware.
166  * @hardware_version_minor: The minor version of the hardware.
167  * @firmware_version_major: The major version of the firmware.
168  * @firmware_version_minor: The minor version of the firmware.
169  *
170  * Represents information about a PKCS11 slot.
171  *
172  * This is analogous to a CK_SLOT_INFO structure, but the
173  * strings are far more usable.
174  *
175  * When you're done with this structure it should be released with
176  * gck_slot_info_free().
177  */
178 
G_DEFINE_BOXED_TYPE(GckSlotInfo,gck_slot_info,gck_slot_info_copy,gck_slot_info_free)179 G_DEFINE_BOXED_TYPE (GckSlotInfo, gck_slot_info,
180                      gck_slot_info_copy, gck_slot_info_free)
181 
182 /**
183  * gck_slot_info_copy:
184  * @slot_info: a slot info
185  *
186  * Make a copy of the slot info.
187  *
188  * Returns: (transfer full): a newly allocated copy slot info
189  */
190 GckSlotInfo *
191 gck_slot_info_copy (GckSlotInfo *slot_info)
192 {
193 	if (slot_info == NULL)
194 		return NULL;
195 
196 	slot_info = g_memdup (slot_info, sizeof (GckSlotInfo));
197 	slot_info->manufacturer_id = g_strdup (slot_info->manufacturer_id);
198 	slot_info->slot_description = g_strdup (slot_info->slot_description);
199 
200 	return slot_info;
201 }
202 
203 
204 /**
205  * gck_slot_info_free:
206  * @slot_info: The slot info to free, or %NULL.
207  *
208  * Free the GckSlotInfo and associated resources.
209  **/
210 void
gck_slot_info_free(GckSlotInfo * slot_info)211 gck_slot_info_free (GckSlotInfo *slot_info)
212 {
213 	if (!slot_info)
214 		return;
215 	g_free (slot_info->slot_description);
216 	g_free (slot_info->manufacturer_id);
217 	g_free (slot_info);
218 }
219 
220 /**
221  * GckTokenInfo:
222  * @label: The displayable token label.
223  * @manufacturer_id: The manufacturer of this slot.
224  * @model: The token model number as a string.
225  * @serial_number: The token serial number as a string.
226  * @flags: Various PKCS11 flags that apply to this token.
227  * @max_session_count: The maximum number of sessions allowed on this token.
228  * @session_count: The number of sessions open on this token.
229  * @max_rw_session_count: The maximum number of read/write sessions allowed on this token.
230  * @rw_session_count: The number of sessions open on this token.
231  * @max_pin_len: The maximum length of a PIN for locking this token.
232  * @min_pin_len: The minimum length of a PIN for locking this token.
233  * @total_public_memory: The total amount of memory on this token for storing public objects.
234  * @free_public_memory: The available amount of memory on this token for storing public objects.
235  * @total_private_memory: The total amount of memory on this token for storing private objects.
236  * @free_private_memory: The available amount of memory on this token for storing private objects.
237  * @hardware_version_major: The major version of the hardware.
238  * @hardware_version_minor: The minor version of the hardware.
239  * @firmware_version_major: The major version of the firmware.
240  * @firmware_version_minor: The minor version of the firmware.
241  * @utc_time: If the token has a hardware clock, this is set to the number of seconds since the epoch.
242  *
243  * Represents information about a PKCS11 token.
244  *
245  * This is analogous to a CK_TOKEN_INFO structure, but the
246  * strings are far more usable.
247  *
248  * When you're done with this structure it should be released with
249  * gck_token_info_free().
250  */
251 
G_DEFINE_BOXED_TYPE(GckTokenInfo,gck_token_info,gck_token_info_copy,gck_token_info_free)252 G_DEFINE_BOXED_TYPE (GckTokenInfo, gck_token_info,
253                      gck_token_info_copy, gck_token_info_free)
254 
255 /**
256  * gck_token_info_copy:
257  * @token_info: a token info
258  *
259  * Make a copy of the token info.
260  *
261  * Returns: (transfer full): a newly allocated copy token info
262  */
263 GckTokenInfo *
264 gck_token_info_copy (GckTokenInfo *token_info)
265 {
266 	if (token_info == NULL)
267 		return NULL;
268 
269 	token_info = g_memdup (token_info, sizeof (GckTokenInfo));
270 	token_info->label = g_strdup (token_info->label);
271 	token_info->manufacturer_id = g_strdup (token_info->manufacturer_id);
272 	token_info->model = g_strdup (token_info->model);
273 	token_info->serial_number = g_strdup (token_info->serial_number);
274 	return token_info;
275 }
276 
277 /**
278  * gck_token_info_free:
279  * @token_info: The token info to free, or %NULL.
280  *
281  * Free the GckTokenInfo and associated resources.
282  **/
283 void
gck_token_info_free(GckTokenInfo * token_info)284 gck_token_info_free (GckTokenInfo *token_info)
285 {
286 	if (!token_info)
287 		return;
288 	g_free (token_info->label);
289 	g_free (token_info->manufacturer_id);
290 	g_free (token_info->model);
291 	g_free (token_info->serial_number);
292 	g_free (token_info);
293 }
294 
295 /**
296  * GckMechanismInfo:
297  * @min_key_size: The minimum key size that can be used with this mechanism.
298  * @max_key_size: The maximum key size that can be used with this mechanism.
299  * @flags: Various PKCS11 flags that apply to this mechanism.
300  *
301  * Represents information about a PKCS11 mechanism.
302  *
303  * This is analogous to a CK_MECHANISM_INFO structure.
304  *
305  * When you're done with this structure it should be released with
306  * gck_mechanism_info_free().
307  */
308 
G_DEFINE_BOXED_TYPE(GckMechanismInfo,gck_mechanism_info,gck_mechanism_info_copy,gck_mechanism_info_free)309 G_DEFINE_BOXED_TYPE (GckMechanismInfo, gck_mechanism_info,
310                      gck_mechanism_info_copy, gck_mechanism_info_free)
311 
312 /**
313  * gck_mechanism_info_copy:
314  * @mech_info: a mechanism info
315  *
316  * Make a copy of the mechanism info.
317  *
318  * Returns: (transfer full): a newly allocated copy mechanism info
319  */
320 GckMechanismInfo *
321 gck_mechanism_info_copy (GckMechanismInfo *mech_info)
322 {
323 	return g_memdup (mech_info, sizeof (GckMechanismInfo));
324 }
325 
326 /**
327  * gck_mechanism_info_free:
328  * @mech_info: The mechanism info to free, or %NULL.
329  *
330  * Free the GckMechanismInfo and associated resources.
331  **/
332 void
gck_mechanism_info_free(GckMechanismInfo * mech_info)333 gck_mechanism_info_free (GckMechanismInfo *mech_info)
334 {
335 	if (!mech_info)
336 		return;
337 	g_free (mech_info);
338 }
339 
340 /**
341  * GckMechanisms:
342  *
343  * A set of GckMechanismInfo structures.
344  */
345 
346 /**
347  * gck_mechanisms_length:
348  * @a: A GckMechanisms set.
349  *
350  * Get the number of GckMechanismInfo in the set.
351  *
352  * Returns: The number in the set.
353  */
354 
355 /**
356  * gck_mechanisms_at:
357  * @a: A GckMechanisms set.
358  * @i: The index of a mechanism
359  *
360  * Get a specific mechanism in a the set.
361  *
362  * Returns: the mechanism
363  */
364 
365 /**
366  * gck_mechanisms_free:
367  * @a: A GckMechanism set.
368  *
369  * Free a GckMechanisms set.
370  */
371 
372 /**
373  * gck_mechanisms_check:
374  * @mechanisms: (element-type ulong): A list of mechanisms, perhaps
375  *              retrieved from gck_slot_get_mechanisms().
376  * @...: A list of mechanism types followed by GCK_INVALID.
377  *
378  * Check whether all the mechanism types are in the list.
379  *
380  * The arguments should be a list of CKM_XXX mechanism types. The last argument
381  * should be GCK_INVALID.
382  *
383  * Return value: Whether the mechanism is in the list or not.
384  **/
385 gboolean
gck_mechanisms_check(GArray * mechanisms,...)386 gck_mechanisms_check (GArray *mechanisms, ...)
387 {
388 	gboolean found = TRUE;
389 	va_list va;
390 	gulong mech;
391 	gsize i;
392 
393 	g_return_val_if_fail (mechanisms != NULL, FALSE);
394 
395 	va_start (va, mechanisms);
396 	for (;;) {
397 		mech = va_arg (va, gulong);
398 		if (mech == GCK_INVALID)
399 			break;
400 
401 		found = FALSE;
402 		for (i = 0; i < gck_mechanisms_length (mechanisms); ++i) {
403 			if (gck_mechanisms_at (mechanisms, i) == mech) {
404 				found = TRUE;
405 				break;
406 			}
407 		}
408 
409 		if (found == FALSE)
410 			break;
411 
412 	}
413 	va_end (va);
414 
415 	return found;
416 }
417 
418 /**
419  * gck_slot_equal:
420  * @slot1: (type Gck.Slot): a pointer to the first #GckSlot
421  * @slot2: (type Gck.Slot): a pointer to the second #GckSlot
422  *
423  * Checks equality of two slots. Two GckSlot objects can point to the same
424  * underlying PKCS\#11 slot.
425  *
426  * Return value: %TRUE if slot1 and slot2 are equal.
427  *               %FALSE if either is not a GckSlot.
428  **/
429 gboolean
gck_slot_equal(gconstpointer slot1,gconstpointer slot2)430 gck_slot_equal (gconstpointer slot1, gconstpointer slot2)
431 {
432 	GckSlot *s1, *s2;
433 
434 	if (slot1 == slot2)
435 		return TRUE;
436 	if (!GCK_IS_SLOT (slot1) || !GCK_IS_SLOT (slot2))
437 		return FALSE;
438 
439 	s1 = GCK_SLOT (slot1);
440 	s2 = GCK_SLOT (slot2);
441 
442 	return s1->pv->handle == s2->pv->handle &&
443 	       gck_module_equal (s1->pv->module, s2->pv->module);
444 }
445 
446 /**
447  * gck_slot_hash:
448  * @slot: (type Gck.Slot): a pointer to a #GckSlot
449  *
450  * Create a hash value for the GckSlot.
451  *
452  * This function is intended for easily hashing a GckSlot to add to
453  * a GHashTable or similar data structure.
454  *
455  * Return value: An integer that can be used as a hash value, or 0 if invalid.
456  **/
457 guint
gck_slot_hash(gconstpointer slot)458 gck_slot_hash (gconstpointer slot)
459 {
460 	GckSlot *self;
461 
462 	g_return_val_if_fail (GCK_IS_SLOT (slot), 0);
463 
464 	self = GCK_SLOT (slot);
465 
466 	return _gck_ulong_hash (&self->pv->handle) ^
467 	       gck_module_hash (self->pv->module);
468 }
469 
470 /**
471  * gck_slot_from_handle:
472  * @module: The module that this slot is on.
473  * @slot_id: The raw PKCS\#11 handle or slot id of this slot.
474  *
475  * Create a new GckSlot object for a raw PKCS\#11 handle.
476  *
477  * Returns: (transfer full): The new GckSlot object.
478  **/
479 GckSlot *
gck_slot_from_handle(GckModule * module,gulong slot_id)480 gck_slot_from_handle (GckModule *module,
481                       gulong slot_id)
482 {
483 	return g_object_new (GCK_TYPE_SLOT,
484 	                     "module", module,
485 	                     "handle", slot_id,
486 	                     NULL);
487 }
488 
489 /**
490  * gck_slot_get_handle:
491  * @self: The slot to get the handle of.
492  *
493  * Get the raw PKCS\#11 handle of a slot.
494  *
495  * Return value: the raw CK_SLOT_ID handle
496  **/
497 gulong
gck_slot_get_handle(GckSlot * self)498 gck_slot_get_handle (GckSlot *self)
499 {
500 	g_return_val_if_fail (GCK_IS_SLOT (self), (CK_SLOT_ID)-1);
501 	return self->pv->handle;
502 }
503 
504 /**
505  * gck_slot_get_module:
506  * @self: The slot to get the module for.
507  *
508  * Get the module that this slot is on.
509  *
510  * Returns: (transfer full): The module, you must unreference this after
511  *          you're done with it.
512  */
513 GckModule *
gck_slot_get_module(GckSlot * self)514 gck_slot_get_module (GckSlot *self)
515 {
516 	g_return_val_if_fail (GCK_IS_SLOT (self), NULL);
517 	g_return_val_if_fail (GCK_IS_MODULE (self->pv->module), NULL);
518 	return g_object_ref (self->pv->module);
519 }
520 
521 /**
522  * gck_slot_get_info:
523  * @self: The slot to get info for.
524  *
525  * Get the information for this slot.
526  *
527  * Returns: (transfer full): the slot information, when done, use gck_slot_info_free()
528  *          to release it.
529  **/
530 GckSlotInfo *
gck_slot_get_info(GckSlot * self)531 gck_slot_get_info (GckSlot *self)
532 {
533 	CK_SLOT_ID handle = (CK_SLOT_ID)-1;
534 	GckModule *module = NULL;
535 	CK_FUNCTION_LIST_PTR funcs;
536 	GckSlotInfo *slotinfo;
537 	CK_SLOT_INFO info;
538 	CK_RV rv;
539 
540 	g_return_val_if_fail (GCK_IS_SLOT (self), NULL);
541 
542 	g_object_get (self, "module", &module, "handle", &handle, NULL);
543 	g_return_val_if_fail (GCK_IS_MODULE (module), NULL);
544 
545 	funcs = gck_module_get_functions (module);
546 	g_return_val_if_fail (funcs, NULL);
547 
548 	memset (&info, 0, sizeof (info));
549 	rv = (funcs->C_GetSlotInfo) (handle, &info);
550 
551 	g_object_unref (module);
552 
553 	if (rv != CKR_OK) {
554 		g_warning ("couldn't get slot info: %s", gck_message_from_rv (rv));
555 		return NULL;
556 	}
557 
558 	slotinfo = g_new0 (GckSlotInfo, 1);
559 	slotinfo->slot_description = gck_string_from_chars (info.slotDescription,
560 	                                                     sizeof (info.slotDescription));
561 	slotinfo->manufacturer_id = gck_string_from_chars (info.manufacturerID,
562 	                                                    sizeof (info.manufacturerID));
563 	slotinfo->flags = info.flags;
564 	slotinfo->hardware_version_major = info.hardwareVersion.major;
565 	slotinfo->hardware_version_minor = info.hardwareVersion.minor;
566 	slotinfo->firmware_version_major = info.firmwareVersion.major;
567 	slotinfo->firmware_version_minor = info.firmwareVersion.minor;
568 
569 	return slotinfo;
570 }
571 
572 GckTokenInfo*
_gck_token_info_from_pkcs11(CK_TOKEN_INFO_PTR info)573 _gck_token_info_from_pkcs11 (CK_TOKEN_INFO_PTR info)
574 {
575 	GckTokenInfo *token_info;
576 	gchar *string;
577 	/* Must be zero-filled, because strptime will leave tm_isdst
578 	 * unchanged */
579 	struct tm tm = { 0 };
580 
581 	token_info = g_new0 (GckTokenInfo, 1);
582 	token_info->label = gck_string_from_chars (info->label, sizeof (info->label));
583 	token_info->model = gck_string_from_chars (info->model, sizeof (info->model));
584 	token_info->manufacturer_id = gck_string_from_chars (info->manufacturerID,
585 	                                                     sizeof (info->manufacturerID));
586 	token_info->serial_number = gck_string_from_chars (info->serialNumber,
587 	                                                   sizeof (info->serialNumber));
588 	token_info->flags = info->flags;
589 	token_info->max_session_count = info->ulMaxSessionCount;
590 	token_info->session_count = info->ulSessionCount;
591 	token_info->max_rw_session_count = info->ulMaxRwSessionCount;
592 	token_info->rw_session_count = info->ulRwSessionCount;
593 	token_info->max_pin_len = info->ulMaxPinLen;
594 	token_info->min_pin_len = info->ulMinPinLen;
595 	token_info->total_public_memory = info->ulTotalPublicMemory;
596 	token_info->total_private_memory = info->ulTotalPrivateMemory;
597 	token_info->free_private_memory = info->ulFreePrivateMemory;
598 	token_info->free_public_memory = info->ulFreePublicMemory;
599 	token_info->hardware_version_major = info->hardwareVersion.major;
600 	token_info->hardware_version_minor = info->hardwareVersion.minor;
601 	token_info->firmware_version_major = info->firmwareVersion.major;
602 	token_info->firmware_version_minor = info->firmwareVersion.minor;
603 
604 	/* Parse the time into seconds since epoch */
605 	if (info->flags & CKF_CLOCK_ON_TOKEN) {
606 		string = g_strndup ((gchar*)info->utcTime, MIN (14, sizeof (info->utcTime)));
607 		if (!strptime (string, "%Y%m%d%H%M%S", &tm))
608 			token_info->utc_time = -1;
609 		else
610 			token_info->utc_time = timegm (&tm);
611 		g_free (string);
612 	} else {
613 		token_info->utc_time = -1;
614 	}
615 
616 	return token_info;
617 }
618 
619 void
_gck_token_info_to_pkcs11(GckTokenInfo * token_info,CK_TOKEN_INFO_PTR info)620 _gck_token_info_to_pkcs11 (GckTokenInfo *token_info, CK_TOKEN_INFO_PTR info)
621 {
622 	gchar buffer[64];
623 	struct tm tm;
624 	time_t tim;
625 	gsize len;
626 
627 	if (!gck_string_to_chars (info->label,
628 	                          sizeof (info->label),
629 	                          token_info->label))
630 		g_return_if_reached ();
631 	if (!gck_string_to_chars (info->model,
632 	                          sizeof (info->model),
633 	                          token_info->model))
634 		g_return_if_reached ();
635 	if (!gck_string_to_chars (info->manufacturerID,
636 	                          sizeof (info->manufacturerID),
637 	                          token_info->manufacturer_id))
638 		g_return_if_reached ();
639 	if (!gck_string_to_chars (info->serialNumber,
640 	                          sizeof (info->serialNumber),
641 	                          token_info->serial_number))
642 		g_return_if_reached ();
643 
644 	info->flags = token_info->flags;
645 	info->ulMaxSessionCount = token_info->max_session_count;
646 	info->ulSessionCount = token_info->session_count;
647 	info->ulMaxRwSessionCount = token_info->max_rw_session_count;
648 	info->ulRwSessionCount = token_info->rw_session_count;
649 	info->ulMaxPinLen = token_info->max_pin_len;
650 	info->ulMinPinLen = token_info->min_pin_len;
651 	info->ulTotalPublicMemory = token_info->total_public_memory;
652 	info->ulTotalPrivateMemory = token_info->total_private_memory;
653 	info->ulFreePrivateMemory = token_info->free_private_memory;
654 	info->ulFreePublicMemory = token_info->free_public_memory;
655 	info->hardwareVersion.major = token_info->hardware_version_major;
656 	info->hardwareVersion.minor = token_info->hardware_version_minor;
657 	info->firmwareVersion.major = token_info->firmware_version_major;
658 	info->firmwareVersion.minor = token_info->firmware_version_minor;
659 
660 	/* Parse the time into seconds since epoch */
661 	if (token_info->flags & CKF_CLOCK_ON_TOKEN) {
662 		tim = token_info->utc_time;
663 		if (!gmtime_r (&tim, &tm))
664 			g_return_if_reached ();
665 		len = strftime (buffer, sizeof (buffer), "%Y%m%d%H%M%S", &tm);
666 		g_return_if_fail (len == sizeof (info->utcTime));
667 		memcpy (info->utcTime, buffer, sizeof (info->utcTime));
668 	} else {
669 		memset (info->utcTime, 0, sizeof (info->utcTime));
670 	}
671 }
672 
673 /**
674  * gck_slot_get_token_info:
675  * @self: The slot to get info for.
676  *
677  * Get the token information for this slot.
678  *
679  * Returns: (transfer full): the token information; when done, use gck_token_info_free()
680  *          to release it
681  **/
682 GckTokenInfo *
gck_slot_get_token_info(GckSlot * self)683 gck_slot_get_token_info (GckSlot *self)
684 {
685 	CK_SLOT_ID handle = (CK_SLOT_ID)-1;
686 	CK_FUNCTION_LIST_PTR funcs;
687 	GckModule *module = NULL;
688 	CK_TOKEN_INFO info;
689 	CK_RV rv;
690 
691 	g_return_val_if_fail (GCK_IS_SLOT (self), NULL);
692 
693 	g_object_get (self, "module", &module, "handle", &handle, NULL);
694 	g_return_val_if_fail (GCK_IS_MODULE (module), NULL);
695 
696 	funcs = gck_module_get_functions (module);
697 	g_return_val_if_fail (funcs, NULL);
698 
699 	memset (&info, 0, sizeof (info));
700 	rv = (funcs->C_GetTokenInfo) (handle, &info);
701 
702 	g_object_unref (module);
703 
704 	if (rv != CKR_OK) {
705 		g_warning ("couldn't get token info: %s", gck_message_from_rv (rv));
706 		return NULL;
707 	}
708 
709 	return _gck_token_info_from_pkcs11 (&info);
710 }
711 
712 /**
713  * gck_slot_get_mechanisms:
714  * @self: The slot to get mechanisms for.
715  *
716  * Get the available mechanisms for this slot.
717  *
718  * Returns: (transfer full) (element-type ulong): a list of the mechanisms
719  *          for this slot, which should be freed with g_array_free ()
720  **/
721 GArray *
gck_slot_get_mechanisms(GckSlot * self)722 gck_slot_get_mechanisms (GckSlot *self)
723 {
724 	CK_SLOT_ID handle = (CK_SLOT_ID)-1;
725 	CK_FUNCTION_LIST_PTR funcs;
726 	GckModule *module = NULL;
727 	CK_MECHANISM_TYPE_PTR mech_list = NULL;
728 	CK_ULONG count, i;
729 	GArray *result;
730 	CK_RV rv;
731 
732 	g_return_val_if_fail (GCK_IS_SLOT (self), NULL);
733 
734 	g_object_get (self, "module", &module, "handle", &handle, NULL);
735 	g_return_val_if_fail (GCK_IS_MODULE (module), NULL);
736 
737 	funcs = gck_module_get_functions (module);
738 	g_return_val_if_fail (funcs, NULL);
739 
740 	rv = (funcs->C_GetMechanismList) (handle, NULL, &count);
741 	if (rv != CKR_OK) {
742 		g_warning ("couldn't get mechanism count: %s", gck_message_from_rv (rv));
743 		count = 0;
744 	} else {
745 		mech_list = g_new (CK_MECHANISM_TYPE, count);
746 		rv = (funcs->C_GetMechanismList) (handle, mech_list, &count);
747 		if (rv != CKR_OK) {
748 			g_warning ("couldn't get mechanism list: %s", gck_message_from_rv (rv));
749 			g_free (mech_list);
750 			count = 0;
751 		}
752 	}
753 
754 	g_object_unref (module);
755 
756 	if (!count)
757 		return NULL;
758 
759 	result = g_array_new (FALSE, TRUE, sizeof (CK_MECHANISM_TYPE));
760 	for (i = 0; i < count; ++i)
761 		g_array_append_val (result, mech_list[i]);
762 
763 	g_free (mech_list);
764 	return result;
765 
766 }
767 
768 /**
769  * gck_slot_get_mechanism_info:
770  * @self: The slot to get mechanism info from.
771  * @mech_type: The mechanisms type to get info for.
772  *
773  * Get information for the specified mechanism.
774  *
775  * Returns: (transfer full): the mechanism information, or %NULL if failed; use
776  *          gck_mechanism_info_free() when done with it
777  **/
778 GckMechanismInfo*
gck_slot_get_mechanism_info(GckSlot * self,gulong mech_type)779 gck_slot_get_mechanism_info (GckSlot *self, gulong mech_type)
780 {
781 	CK_SLOT_ID handle = (CK_SLOT_ID)-1;
782 	CK_FUNCTION_LIST_PTR funcs;
783 	GckMechanismInfo *mechinfo;
784 	GckModule *module = NULL;
785 	CK_MECHANISM_INFO info;
786 	struct tm;
787 	CK_RV rv;
788 
789 	g_return_val_if_fail (GCK_IS_SLOT (self), NULL);
790 
791 	g_object_get (self, "module", &module, "handle", &handle, NULL);
792 	g_return_val_if_fail (GCK_IS_MODULE (module), NULL);
793 
794 	funcs = gck_module_get_functions (module);
795 	g_return_val_if_fail (funcs, NULL);
796 
797 	memset (&info, 0, sizeof (info));
798 	rv = (funcs->C_GetMechanismInfo) (handle, mech_type, &info);
799 
800 	g_object_unref (module);
801 
802 	if (rv != CKR_OK) {
803 		g_warning ("couldn't get mechanism info: %s", gck_message_from_rv (rv));
804 		return NULL;
805 	}
806 
807 	mechinfo = g_new0 (GckMechanismInfo, 1);
808 	mechinfo->flags = info.flags;
809 	mechinfo->max_key_size = info.ulMaxKeySize;
810 	mechinfo->min_key_size = info.ulMinKeySize;
811 
812 	return mechinfo;
813 }
814 
815 /**
816  * gck_slot_has_flags:
817  * @self: The GckSlot object.
818  * @flags: The flags to check.
819  *
820  * Check if the PKCS11 slot has the given flags.
821  *
822  * Returns: Whether one or more flags exist.
823  */
824 gboolean
gck_slot_has_flags(GckSlot * self,gulong flags)825 gck_slot_has_flags (GckSlot *self, gulong flags)
826 {
827 	CK_FUNCTION_LIST_PTR funcs;
828 	GckModule *module = NULL;
829 	CK_SLOT_INFO info;
830 	CK_SLOT_ID handle;
831 	CK_RV rv;
832 
833 	g_return_val_if_fail (GCK_IS_SLOT (self), FALSE);
834 
835 	g_object_get (self, "module", &module, "handle", &handle, NULL);
836 	g_return_val_if_fail (GCK_IS_MODULE (module), FALSE);
837 
838 	funcs = gck_module_get_functions (module);
839 	g_return_val_if_fail (funcs, FALSE);
840 
841 	memset (&info, 0, sizeof (info));
842 	rv = (funcs->C_GetSlotInfo) (handle, &info);
843 
844 	g_object_unref (module);
845 
846 	if (rv != CKR_OK) {
847 		g_warning ("couldn't get slot info: %s", gck_message_from_rv (rv));
848 		return FALSE;
849 	}
850 
851 	return (info.flags & flags) != 0;
852 }
853 
854 /**
855  * gck_slot_token_has_flags:
856  * @self: The GckSlot object.
857  * @flags: The flags to check.
858  *
859  * Check if the PKCS11 token in the slot has the given flags.
860  *
861  * Returns: Whether one or more flags exist.
862  */
863 gboolean
gck_slot_token_has_flags(GckSlot * self,gulong flags)864 gck_slot_token_has_flags (GckSlot *self, gulong flags)
865 {
866 	CK_FUNCTION_LIST_PTR funcs;
867 	GckModule *module = NULL;
868 	CK_TOKEN_INFO info;
869 	CK_SLOT_ID handle;
870 	CK_RV rv;
871 
872 	g_return_val_if_fail (GCK_IS_SLOT (self), FALSE);
873 
874 	g_object_get (self, "module", &module, "handle", &handle, NULL);
875 	g_return_val_if_fail (GCK_IS_MODULE (module), FALSE);
876 
877 	funcs = gck_module_get_functions (module);
878 	g_return_val_if_fail (funcs, FALSE);
879 
880 	memset (&info, 0, sizeof (info));
881 	rv = (funcs->C_GetTokenInfo) (handle, &info);
882 
883 	g_object_unref (module);
884 
885 	if (rv != CKR_OK) {
886 		g_warning ("couldn't get slot info: %s", gck_message_from_rv (rv));
887 		return FALSE;
888 	}
889 
890 	return (info.flags & flags) != 0;
891 }
892 
893 /**
894  * gck_slot_enumerate_objects:
895  * @self: a #GckSlot to enumerate objects on
896  * @match: attributes that the objects must match, or empty for all objects
897  * @options: options for opening a session
898  *
899  * Setup an enumerator for listing matching objects on the slot.
900  *
901  * If the @match #GckAttributes is floating, it is consumed.
902  *
903  * This call will not block but will return an enumerator immediately.
904  *
905  * Returns: (transfer full): a new enumerator
906  **/
907 GckEnumerator *
gck_slot_enumerate_objects(GckSlot * self,GckAttributes * match,GckSessionOptions options)908 gck_slot_enumerate_objects (GckSlot *self,
909                             GckAttributes *match,
910                             GckSessionOptions options)
911 {
912 	GList *slots = NULL;
913 	GckEnumerator *enumerator;
914 
915 	g_return_val_if_fail (GCK_IS_SLOT (self), NULL);
916 	g_return_val_if_fail (match != NULL, NULL);
917 
918 	slots = g_list_append (slots, self);
919 	enumerator = gck_slots_enumerate_objects (slots, match, options);
920 	g_list_free (slots);
921 
922 	return enumerator;
923 }
924 
925 /**
926  * gck_slots_enumerate_objects:
927  * @slots: (element-type Gck.Slot): a list of #GckSlot to enumerate objects on.
928  * @match: attributes that the objects must match, or empty for all objects
929  * @options: options for opening a session
930  *
931  * Setup an enumerator for listing matching objects on the slots.
932  *
933  * If the @match #GckAttributes is floating, it is consumed.
934  *
935  * This call will not block but will return an enumerator immediately.
936  *
937  * Returns: (transfer full): a new enumerator
938  **/
939 GckEnumerator*
gck_slots_enumerate_objects(GList * slots,GckAttributes * match,GckSessionOptions options)940 gck_slots_enumerate_objects (GList *slots,
941                              GckAttributes *match,
942                              GckSessionOptions options)
943 {
944 	GckUriData *uri_data;
945 
946 	g_return_val_if_fail (match != NULL, NULL);
947 
948 	uri_data = gck_uri_data_new ();
949 	uri_data->attributes = gck_attributes_ref_sink (match);
950 
951 	return _gck_enumerator_new_for_slots (slots, options, uri_data);
952 }
953 
954 
955 /**
956  * gck_slot_open_session:
957  * @self: The slot ot open a session on.
958  * @options: The #GckSessionOptions to open a session with.
959  * @cancellable: An optional cancellation object, or %NULL.
960  * @error: A location to return an error, or %NULL.
961  *
962  * Open a session on the slot. If the 'auto reuse' setting is set,
963  * then this may be a recycled session with the same flags.
964  *
965  * This call may block for an indefinite period.
966  *
967  * Returns: (transfer full): a new session or %NULL if an error occurs
968  **/
969 GckSession *
gck_slot_open_session(GckSlot * self,GckSessionOptions options,GCancellable * cancellable,GError ** error)970 gck_slot_open_session (GckSlot *self,
971                        GckSessionOptions options,
972                        GCancellable *cancellable,
973                        GError **error)
974 {
975 	return gck_slot_open_session_full (self, options, 0, NULL, NULL, cancellable, error);
976 }
977 
978 /**
979  * gck_slot_open_session_full: (skip)
980  * @self: The slot to open a session on.
981  * @options: The options to open the new session with.
982  * @pkcs11_flags: Additional raw PKCS\#11 flags.
983  * @app_data: Application data for notification callback.
984  * @notify: PKCS\#11 notification callback.
985  * @cancellable: Optional cancellation object, or %NULL.
986  * @error: A location to return an error, or %NULL.
987  *
988  * Open a session on the slot. If the 'auto reuse' setting is set,
989  * then this may be a recycled session with the same flags.
990  *
991  * This call may block for an indefinite period.
992  *
993  * Returns: (transfer full): a new session or %NULL if an error occurs
994  **/
995 GckSession *
gck_slot_open_session_full(GckSlot * self,GckSessionOptions options,gulong pkcs11_flags,gpointer app_data,CK_NOTIFY notify,GCancellable * cancellable,GError ** error)996 gck_slot_open_session_full (GckSlot *self,
997                             GckSessionOptions options,
998                             gulong pkcs11_flags,
999                             gpointer app_data,
1000                             CK_NOTIFY notify,
1001                             GCancellable *cancellable,
1002                             GError **error)
1003 {
1004 	return g_initable_new (GCK_TYPE_SESSION, cancellable, error,
1005 	                       "options", options,
1006 	                       "slot", self,
1007 	                       "opening-flags", pkcs11_flags,
1008 	                       "app-data", app_data,
1009 	                       NULL);
1010 }
1011 
1012 /**
1013  * gck_slot_open_session_async:
1014  * @self: The slot to open a session on.
1015  * @options: The options to open the new session with.
1016  * @cancellable: Optional cancellation object, or %NULL.
1017  * @callback: Called when the operation completes.
1018  * @user_data: Data to pass to the callback.
1019  *
1020  * Open a session on the slot. If the 'auto reuse' setting is set,
1021  * then this may be a recycled session with the same flags.
1022  *
1023  * This call will return immediately and complete asynchronously.
1024  **/
1025 void
gck_slot_open_session_async(GckSlot * self,GckSessionOptions options,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1026 gck_slot_open_session_async (GckSlot *self,
1027                              GckSessionOptions options,
1028                              GCancellable *cancellable,
1029                              GAsyncReadyCallback callback,
1030                              gpointer user_data)
1031 {
1032 	gck_slot_open_session_full_async (self, options, 0UL, NULL, NULL, cancellable, callback, user_data);
1033 }
1034 
1035 static void
on_open_session_complete(GObject * source,GAsyncResult * result,gpointer user_data)1036 on_open_session_complete (GObject *source,
1037                           GAsyncResult *result,
1038                           gpointer user_data)
1039 {
1040 	GTask *task = G_TASK (user_data);
1041 	GError *error = NULL;
1042 	GObject *session;
1043 
1044 	session = g_async_initable_new_finish (G_ASYNC_INITABLE (source), result, &error);
1045 	if (session != NULL)
1046 		g_task_return_pointer (task, session, g_object_unref);
1047 	else
1048 		g_task_return_error (task, g_steal_pointer (&error));
1049 
1050 	g_clear_object (&task);
1051 }
1052 
1053 /**
1054  * gck_slot_open_session_full_async: (skip)
1055  * @self: The slot to open a session on.
1056  * @options: Options to open the new session with.
1057  * @pkcs11_flags: Additional raw PKCS\#11 flags.
1058  * @app_data: Application data for notification callback.
1059  * @notify: PKCS\#11 notification callback.
1060  * @cancellable: (nullable): Optional cancellation object, or %NULL.
1061  * @callback: Called when the operation completes.
1062  * @user_data: Data to pass to the callback.
1063  *
1064  * Open a session on the slot. If the 'auto reuse' setting is set,
1065  * then this may be a recycled session with the same flags.
1066  *
1067  * This call will return immediately and complete asynchronously.
1068  **/
1069 void
gck_slot_open_session_full_async(GckSlot * self,GckSessionOptions options,gulong pkcs11_flags,gpointer app_data,CK_NOTIFY notify,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1070 gck_slot_open_session_full_async (GckSlot *self,
1071                                   GckSessionOptions options,
1072                                   gulong pkcs11_flags,
1073                                   gpointer app_data,
1074                                   CK_NOTIFY notify,
1075                                   GCancellable *cancellable,
1076                                   GAsyncReadyCallback callback,
1077                                   gpointer user_data)
1078 {
1079 	GTask *task;
1080 
1081 	g_return_if_fail (GCK_IS_SLOT (self));
1082 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1083 
1084 	task = g_task_new (self, cancellable, callback, user_data);
1085 	g_task_set_source_tag (task, gck_slot_open_session_full_async);
1086 
1087 	g_async_initable_new_async (GCK_TYPE_SESSION, G_PRIORITY_DEFAULT,
1088 	                            cancellable, on_open_session_complete,
1089 	                            g_steal_pointer (&task),
1090 	                            "options", options,
1091 	                            "slot", self,
1092 	                            "opening-flags", pkcs11_flags,
1093 	                            "app-data", app_data,
1094 	                            NULL);
1095 
1096 	g_clear_object (&task);
1097 }
1098 
1099 /**
1100  * gck_slot_open_session_finish:
1101  * @self: The slot to open a session on.
1102  * @result: The result passed to the callback.
1103  * @error: A location to return an error or %NULL.
1104  *
1105  * Get the result of an open session operation. If the 'auto reuse' setting is set,
1106  * then this may be a recycled session with the same flags.
1107  *
1108  * Returns: (transfer full): the new session or %NULL if an error occurs
1109  */
1110 GckSession *
gck_slot_open_session_finish(GckSlot * self,GAsyncResult * result,GError ** error)1111 gck_slot_open_session_finish (GckSlot *self, GAsyncResult *result, GError **error)
1112 {
1113 	g_return_val_if_fail (GCK_IS_SLOT (self), NULL);
1114 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1115 	g_return_val_if_fail (g_task_is_valid (result, self), NULL);
1116 
1117 	return g_task_propagate_pointer (G_TASK (result), error);
1118 }
1119 
1120 /**
1121  * gck_slot_match:
1122  * @self: the slot to match
1123  * @uri: the uri to match against the slot
1124  *
1125  * Check whether the PKCS\#11 URI matches the slot
1126  *
1127  * Returns: whether the URI matches or not
1128  */
1129 gboolean
gck_slot_match(GckSlot * self,GckUriData * uri)1130 gck_slot_match (GckSlot *self,
1131                 GckUriData *uri)
1132 {
1133 	GckModule *module;
1134 	GckTokenInfo *info;
1135 	gboolean match = TRUE;
1136 
1137 	g_return_val_if_fail (GCK_IS_SLOT (self), FALSE);
1138 	g_return_val_if_fail (uri != NULL, FALSE);
1139 
1140 	if (uri->any_unrecognized)
1141 		match = FALSE;
1142 
1143 	if (match && uri->module_info) {
1144 		module = gck_slot_get_module (self);
1145 		match = gck_module_match (module, uri);
1146 		g_object_unref (module);
1147 	}
1148 
1149 	if (match && uri->token_info) {
1150 		info = gck_slot_get_token_info (self);
1151 		match = _gck_token_info_match (uri->token_info, info);
1152 		gck_token_info_free (info);
1153 	}
1154 
1155 	return match;
1156 }
1157