/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/* gck-slot.c - the GObject PKCS#11 wrapper library
Copyright (C) 2008, Stefan Walter
The Gnome Keyring Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The Gnome Keyring Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the Gnome Library; see the file COPYING.LIB. If not,
see .
Author: Stef Walter
*/
#include "config.h"
#include "gck.h"
#include "gck-private.h"
#include
#include
/**
* GckSlot:
*
* Represents a PKCS#11 slot that can contain a token.
*
* A PKCS#11 slot can contain a token. As an example, a slot might be a card
* reader, and the token the card. If the PKCS#11 module is not a hardware
* driver, often the slot and token are equivalent.
*/
enum {
PROP_0,
PROP_MODULE,
PROP_HANDLE
};
struct _GckSlot {
GObject parent_instance;
GckModule *module;
CK_SLOT_ID handle;
};
G_DEFINE_TYPE (GckSlot, gck_slot, G_TYPE_OBJECT);
/* ----------------------------------------------------------------------------
* OBJECT
*/
static void
gck_slot_init (GckSlot *self)
{
}
static void
gck_slot_get_property (GObject *obj, guint prop_id, GValue *value,
GParamSpec *pspec)
{
GckSlot *self = GCK_SLOT (obj);
switch (prop_id) {
case PROP_MODULE:
g_value_take_object (value, gck_slot_get_module (self));
break;
case PROP_HANDLE:
g_value_set_ulong (value, gck_slot_get_handle (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
break;
}
}
static void
gck_slot_set_property (GObject *obj, guint prop_id, const GValue *value,
GParamSpec *pspec)
{
GckSlot *self = GCK_SLOT (obj);
/* All writes to data members below, happen only during construct phase */
switch (prop_id) {
case PROP_MODULE:
g_assert (!self->module);
self->module = g_value_dup_object (value);
g_assert (self->module);
break;
case PROP_HANDLE:
g_assert (!self->handle);
self->handle = g_value_get_ulong (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
break;
}
}
static void
gck_slot_finalize (GObject *obj)
{
GckSlot *self = GCK_SLOT (obj);
g_clear_object (&self->module);
G_OBJECT_CLASS (gck_slot_parent_class)->finalize (obj);
}
static void
gck_slot_class_init (GckSlotClass *klass)
{
GObjectClass *gobject_class = (GObjectClass*)klass;
gck_slot_parent_class = g_type_class_peek_parent (klass);
gobject_class->get_property = gck_slot_get_property;
gobject_class->set_property = gck_slot_set_property;
gobject_class->finalize = gck_slot_finalize;
/**
* GckSlot:module:
*
* The PKCS11 object that this slot is a part of.
*/
g_object_class_install_property (gobject_class, PROP_MODULE,
g_param_spec_object ("module", "Module", "PKCS11 Module",
GCK_TYPE_MODULE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
/**
* GckSlot:handle:
*
* The raw CK_SLOT_ID handle of this slot.
*/
g_object_class_install_property (gobject_class, PROP_HANDLE,
g_param_spec_ulong ("handle", "Handle", "PKCS11 Slot ID",
0, G_MAXULONG, 0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
}
/* ----------------------------------------------------------------------------
* PUBLIC
*/
/**
* GckSlotInfo:
* @slot_description: Description of the slot.
* @manufacturer_id: The manufacturer of this slot.
* @flags: Various PKCS11 flags that apply to this slot.
* @hardware_version_major: The major version of the hardware.
* @hardware_version_minor: The minor version of the hardware.
* @firmware_version_major: The major version of the firmware.
* @firmware_version_minor: The minor version of the firmware.
*
* Represents information about a PKCS11 slot.
*
* This is analogous to a CK_SLOT_INFO structure, but the
* strings are far more usable.
*
* When you're done with this structure it should be released with
* gck_slot_info_free().
*/
G_DEFINE_BOXED_TYPE (GckSlotInfo, gck_slot_info,
gck_slot_info_copy, gck_slot_info_free)
/**
* gck_slot_info_copy:
* @slot_info: a slot info
*
* Make a copy of the slot info.
*
* Returns: (transfer full): a newly allocated copy slot info
*/
GckSlotInfo *
gck_slot_info_copy (GckSlotInfo *slot_info)
{
if (slot_info == NULL)
return NULL;
slot_info = g_memdup2 (slot_info, sizeof (GckSlotInfo));
slot_info->manufacturer_id = g_strdup (slot_info->manufacturer_id);
slot_info->slot_description = g_strdup (slot_info->slot_description);
return slot_info;
}
/**
* gck_slot_info_free:
* @slot_info: The slot info to free, or %NULL.
*
* Free the GckSlotInfo and associated resources.
**/
void
gck_slot_info_free (GckSlotInfo *slot_info)
{
if (!slot_info)
return;
g_clear_pointer (&slot_info->slot_description, g_free);
g_clear_pointer (&slot_info->manufacturer_id, g_free);
g_clear_pointer (&slot_info, g_free);
}
/**
* GckTokenInfo:
* @label: The displayable token label.
* @manufacturer_id: The manufacturer of this slot.
* @model: The token model number as a string.
* @serial_number: The token serial number as a string.
* @flags: Various PKCS11 flags that apply to this token.
* @max_session_count: The maximum number of sessions allowed on this token.
* @session_count: The number of sessions open on this token.
* @max_rw_session_count: The maximum number of read/write sessions allowed on this token.
* @rw_session_count: The number of sessions open on this token.
* @max_pin_len: The maximum length of a PIN for locking this token.
* @min_pin_len: The minimum length of a PIN for locking this token.
* @total_public_memory: The total amount of memory on this token for storing public objects.
* @free_public_memory: The available amount of memory on this token for storing public objects.
* @total_private_memory: The total amount of memory on this token for storing private objects.
* @free_private_memory: The available amount of memory on this token for storing private objects.
* @hardware_version_major: The major version of the hardware.
* @hardware_version_minor: The minor version of the hardware.
* @firmware_version_major: The major version of the firmware.
* @firmware_version_minor: The minor version of the firmware.
* @utc_time: If the token has a hardware clock, this is the UTC #GDateTime
*
* Represents information about a PKCS#11 token.
*
* This is analogous to a `CK_TOKEN_INFO` structure, but the fields are far
* more usable.
*
* When you're done with this structure it should be released with
* gck_token_info_free().
*/
G_DEFINE_BOXED_TYPE (GckTokenInfo, gck_token_info,
gck_token_info_copy, gck_token_info_free)
/**
* gck_token_info_copy:
* @token_info: a token info
*
* Make a copy of the token info.
*
* Returns: (transfer full): a newly allocated copy token info
*/
GckTokenInfo *
gck_token_info_copy (GckTokenInfo *token_info)
{
if (token_info == NULL)
return NULL;
token_info = g_memdup2 (token_info, sizeof (GckTokenInfo));
token_info->label = g_strdup (token_info->label);
token_info->manufacturer_id = g_strdup (token_info->manufacturer_id);
token_info->model = g_strdup (token_info->model);
token_info->serial_number = g_strdup (token_info->serial_number);
if (token_info->utc_time != NULL)
token_info->utc_time = g_date_time_add (token_info->utc_time, 0);
return token_info;
}
/**
* gck_token_info_free:
* @token_info: The token info to free, or %NULL.
*
* Free the GckTokenInfo and associated resources.
**/
void
gck_token_info_free (GckTokenInfo *token_info)
{
if (!token_info)
return;
g_clear_pointer (&token_info->utc_time, g_date_time_unref);
g_free (token_info->label);
g_free (token_info->manufacturer_id);
g_free (token_info->model);
g_free (token_info->serial_number);
g_free (token_info);
}
/**
* GckMechanismInfo:
* @min_key_size: The minimum key size that can be used with this mechanism.
* @max_key_size: The maximum key size that can be used with this mechanism.
* @flags: Various PKCS11 flags that apply to this mechanism.
*
* Represents information about a PKCS11 mechanism.
*
* This is analogous to a CK_MECHANISM_INFO structure.
*
* When you're done with this structure it should be released with
* gck_mechanism_info_free().
*/
G_DEFINE_BOXED_TYPE (GckMechanismInfo, gck_mechanism_info,
gck_mechanism_info_copy, gck_mechanism_info_free)
/**
* gck_mechanism_info_copy:
* @mech_info: a mechanism info
*
* Make a copy of the mechanism info.
*
* Returns: (transfer full): a newly allocated copy mechanism info
*/
GckMechanismInfo *
gck_mechanism_info_copy (GckMechanismInfo *mech_info)
{
return g_memdup2 (mech_info, sizeof (GckMechanismInfo));
}
/**
* gck_mechanism_info_free:
* @mech_info: The mechanism info to free, or %NULL.
*
* Free the GckMechanismInfo and associated resources.
**/
void
gck_mechanism_info_free (GckMechanismInfo *mech_info)
{
if (!mech_info)
return;
g_free (mech_info);
}
/**
* GckMechanisms:
*
* A set of GckMechanismInfo structures.
*/
/**
* gck_mechanisms_length:
* @a: A GckMechanisms set.
*
* Get the number of GckMechanismInfo in the set.
*
* Returns: The number in the set.
*/
/**
* gck_mechanisms_at:
* @a: A GckMechanisms set.
* @i: The index of a mechanism
*
* Get a specific mechanism in a the set.
*
* Returns: the mechanism
*/
/**
* gck_mechanisms_free:
* @a: A GckMechanism set.
*
* Free a GckMechanisms set.
*/
/**
* gck_mechanisms_check:
* @mechanisms: (element-type ulong): A list of mechanisms, perhaps
* retrieved from gck_slot_get_mechanisms().
* @...: A list of mechanism types followed by GCK_INVALID.
*
* Check whether all the mechanism types are in the list.
*
* The arguments should be a list of CKM_XXX mechanism types. The last argument
* should be GCK_INVALID.
*
* Return value: Whether the mechanism is in the list or not.
**/
gboolean
gck_mechanisms_check (GArray *mechanisms, ...)
{
gboolean found = TRUE;
va_list va;
gulong mech;
gsize i;
g_return_val_if_fail (mechanisms != NULL, FALSE);
va_start (va, mechanisms);
for (;;) {
mech = va_arg (va, gulong);
if (mech == GCK_INVALID)
break;
found = FALSE;
for (i = 0; i < gck_mechanisms_length (mechanisms); ++i) {
if (gck_mechanisms_at (mechanisms, i) == mech) {
found = TRUE;
break;
}
}
if (found == FALSE)
break;
}
va_end (va);
return found;
}
/**
* gck_slot_equal:
* @slot1: (type Gck.Slot): a pointer to the first #GckSlot
* @slot2: (type Gck.Slot): a pointer to the second #GckSlot
*
* Checks equality of two slots. Two GckSlot objects can point to the same
* underlying PKCS#11 slot.
*
* Return value: %TRUE if slot1 and slot2 are equal.
* %FALSE if either is not a GckSlot.
**/
gboolean
gck_slot_equal (GckSlot *slot1, GckSlot *slot2)
{
if (slot1 == slot2)
return TRUE;
if (!GCK_IS_SLOT (slot1) || !GCK_IS_SLOT (slot2))
return FALSE;
return slot1->handle == slot2->handle &&
gck_module_equal (slot1->module, slot2->module);
}
/**
* gck_slot_hash:
* @slot: (type Gck.Slot): a pointer to a #GckSlot
*
* Create a hash value for the GckSlot.
*
* This function is intended for easily hashing a GckSlot to add to
* a GHashTable or similar data structure.
*
* Return value: An integer that can be used as a hash value, or 0 if invalid.
**/
guint
gck_slot_hash (GckSlot *slot)
{
g_return_val_if_fail (GCK_IS_SLOT (slot), 0);
return _gck_ulong_hash (&slot->handle) ^
gck_module_hash (slot->module);
}
/**
* gck_slot_from_handle:
* @module: The module that this slot is on.
* @slot_id: The raw PKCS#11 handle or slot id of this slot.
*
* Create a new GckSlot object for a raw PKCS#11 handle.
*
* Returns: (transfer full): The new GckSlot object.
**/
GckSlot *
gck_slot_from_handle (GckModule *module,
gulong slot_id)
{
return g_object_new (GCK_TYPE_SLOT,
"module", module,
"handle", slot_id,
NULL);
}
/**
* gck_slot_get_handle:
* @self: The slot to get the handle of.
*
* Get the raw PKCS#11 handle of a slot.
*
* Return value: the raw CK_SLOT_ID handle
**/
gulong
gck_slot_get_handle (GckSlot *self)
{
g_return_val_if_fail (GCK_IS_SLOT (self), (CK_SLOT_ID)-1);
return self->handle;
}
/**
* gck_slot_get_module:
* @self: The slot to get the module for.
*
* Get the module that this slot is on.
*
* Returns: (transfer full): The module, you must unreference this after
* you're done with it.
*/
GckModule *
gck_slot_get_module (GckSlot *self)
{
g_return_val_if_fail (GCK_IS_SLOT (self), NULL);
g_return_val_if_fail (GCK_IS_MODULE (self->module), NULL);
return g_object_ref (self->module);
}
/**
* gck_slot_get_info:
* @self: The slot to get info for.
*
* Get the information for this slot.
*
* Returns: (transfer full): the slot information, when done, use gck_slot_info_free()
* to release it.
**/
GckSlotInfo *
gck_slot_get_info (GckSlot *self)
{
CK_SLOT_ID handle = (CK_SLOT_ID)-1;
GckModule *module = NULL;
CK_FUNCTION_LIST_PTR funcs;
GckSlotInfo *slotinfo;
CK_SLOT_INFO info;
CK_RV rv;
g_return_val_if_fail (GCK_IS_SLOT (self), NULL);
g_object_get (self, "module", &module, "handle", &handle, NULL);
g_return_val_if_fail (GCK_IS_MODULE (module), NULL);
funcs = gck_module_get_functions (module);
g_return_val_if_fail (funcs, NULL);
memset (&info, 0, sizeof (info));
rv = (funcs->C_GetSlotInfo) (handle, &info);
g_object_unref (module);
if (rv != CKR_OK) {
g_warning ("couldn't get slot info: %s", gck_message_from_rv (rv));
return NULL;
}
slotinfo = g_new0 (GckSlotInfo, 1);
slotinfo->slot_description = gck_string_from_chars (info.slotDescription,
sizeof (info.slotDescription));
slotinfo->manufacturer_id = gck_string_from_chars (info.manufacturerID,
sizeof (info.manufacturerID));
slotinfo->flags = info.flags;
slotinfo->hardware_version_major = info.hardwareVersion.major;
slotinfo->hardware_version_minor = info.hardwareVersion.minor;
slotinfo->firmware_version_major = info.firmwareVersion.major;
slotinfo->firmware_version_minor = info.firmwareVersion.minor;
return slotinfo;
}
GckTokenInfo*
_gck_token_info_from_pkcs11 (CK_TOKEN_INFO_PTR info)
{
GckTokenInfo *token_info;
token_info = g_new0 (GckTokenInfo, 1);
token_info->label = gck_string_from_chars (info->label, sizeof (info->label));
token_info->model = gck_string_from_chars (info->model, sizeof (info->model));
token_info->manufacturer_id = gck_string_from_chars (info->manufacturerID,
sizeof (info->manufacturerID));
token_info->serial_number = gck_string_from_chars (info->serialNumber,
sizeof (info->serialNumber));
token_info->flags = info->flags;
token_info->max_session_count = info->ulMaxSessionCount;
token_info->session_count = info->ulSessionCount;
token_info->max_rw_session_count = info->ulMaxRwSessionCount;
token_info->rw_session_count = info->ulRwSessionCount;
token_info->max_pin_len = info->ulMaxPinLen;
token_info->min_pin_len = info->ulMinPinLen;
token_info->total_public_memory = info->ulTotalPublicMemory;
token_info->total_private_memory = info->ulTotalPrivateMemory;
token_info->free_private_memory = info->ulFreePrivateMemory;
token_info->free_public_memory = info->ulFreePublicMemory;
token_info->hardware_version_major = info->hardwareVersion.major;
token_info->hardware_version_minor = info->hardwareVersion.minor;
token_info->firmware_version_major = info->firmwareVersion.major;
token_info->firmware_version_minor = info->firmwareVersion.minor;
/* Parse the time into seconds since epoch */
if (info->flags & CKF_CLOCK_ON_TOKEN) {
char *string;
GTimeZone *tz;
/* The original string has format "%Y%m%d%H%M%S", which just
* needs a separator still to be iso8601 confirmant */
if (sizeof (info->utcTime) != 14)
token_info->utc_time = NULL;
string = g_strdup_printf ("%.8s %.6s",
(char *) info->utcTime,
((char *) info->utcTime) + 8);
tz = g_time_zone_new_utc ();
token_info->utc_time = g_date_time_new_from_iso8601 (string, tz);
g_time_zone_unref (tz);
g_free (string);
} else {
token_info->utc_time = NULL;
}
return token_info;
}
void
_gck_token_info_to_pkcs11 (GckTokenInfo *token_info, CK_TOKEN_INFO_PTR info)
{
if (!gck_string_to_chars (info->label,
sizeof (info->label),
token_info->label))
g_return_if_reached ();
if (!gck_string_to_chars (info->model,
sizeof (info->model),
token_info->model))
g_return_if_reached ();
if (!gck_string_to_chars (info->manufacturerID,
sizeof (info->manufacturerID),
token_info->manufacturer_id))
g_return_if_reached ();
if (!gck_string_to_chars (info->serialNumber,
sizeof (info->serialNumber),
token_info->serial_number))
g_return_if_reached ();
info->flags = token_info->flags;
info->ulMaxSessionCount = token_info->max_session_count;
info->ulSessionCount = token_info->session_count;
info->ulMaxRwSessionCount = token_info->max_rw_session_count;
info->ulRwSessionCount = token_info->rw_session_count;
info->ulMaxPinLen = token_info->max_pin_len;
info->ulMinPinLen = token_info->min_pin_len;
info->ulTotalPublicMemory = token_info->total_public_memory;
info->ulTotalPrivateMemory = token_info->total_private_memory;
info->ulFreePrivateMemory = token_info->free_private_memory;
info->ulFreePublicMemory = token_info->free_public_memory;
info->hardwareVersion.major = token_info->hardware_version_major;
info->hardwareVersion.minor = token_info->hardware_version_minor;
info->firmwareVersion.major = token_info->firmware_version_major;
info->firmwareVersion.minor = token_info->firmware_version_minor;
/* Parse the time into seconds since epoch */
if (token_info->flags & CKF_CLOCK_ON_TOKEN) {
char *buffer;
buffer = g_date_time_format (token_info->utc_time,
"%Y%m%d%H%M%S");
g_return_if_fail (strlen (buffer) == sizeof (info->utcTime));
memcpy (info->utcTime, buffer, sizeof (info->utcTime));
g_free (buffer);
} else {
memset (info->utcTime, 0, sizeof (info->utcTime));
}
}
/**
* gck_slot_get_token_info:
* @self: The slot to get info for.
*
* Get the token information for this slot.
*
* Returns: (transfer full): the token information; when done, use gck_token_info_free()
* to release it
**/
GckTokenInfo *
gck_slot_get_token_info (GckSlot *self)
{
CK_SLOT_ID handle = (CK_SLOT_ID)-1;
CK_FUNCTION_LIST_PTR funcs;
GckModule *module = NULL;
CK_TOKEN_INFO info;
CK_RV rv;
g_return_val_if_fail (GCK_IS_SLOT (self), NULL);
g_object_get (self, "module", &module, "handle", &handle, NULL);
g_return_val_if_fail (GCK_IS_MODULE (module), NULL);
funcs = gck_module_get_functions (module);
g_return_val_if_fail (funcs, NULL);
memset (&info, 0, sizeof (info));
rv = (funcs->C_GetTokenInfo) (handle, &info);
g_object_unref (module);
if (rv != CKR_OK) {
g_warning ("couldn't get token info: %s", gck_message_from_rv (rv));
return NULL;
}
return _gck_token_info_from_pkcs11 (&info);
}
/**
* gck_slot_get_mechanisms:
* @self: The slot to get mechanisms for.
*
* Get the available mechanisms for this slot.
*
* Returns: (transfer full) (element-type ulong): a list of the mechanisms
* for this slot, which should be freed with g_array_free ()
**/
GArray *
gck_slot_get_mechanisms (GckSlot *self)
{
CK_SLOT_ID handle = (CK_SLOT_ID)-1;
CK_FUNCTION_LIST_PTR funcs;
GckModule *module = NULL;
CK_MECHANISM_TYPE_PTR mech_list = NULL;
CK_ULONG count, i;
GArray *result;
CK_RV rv;
g_return_val_if_fail (GCK_IS_SLOT (self), NULL);
g_object_get (self, "module", &module, "handle", &handle, NULL);
g_return_val_if_fail (GCK_IS_MODULE (module), NULL);
funcs = gck_module_get_functions (module);
g_return_val_if_fail (funcs, NULL);
rv = (funcs->C_GetMechanismList) (handle, NULL, &count);
if (rv != CKR_OK) {
g_warning ("couldn't get mechanism count: %s", gck_message_from_rv (rv));
count = 0;
} else {
mech_list = g_new (CK_MECHANISM_TYPE, count);
rv = (funcs->C_GetMechanismList) (handle, mech_list, &count);
if (rv != CKR_OK) {
g_warning ("couldn't get mechanism list: %s", gck_message_from_rv (rv));
g_free (mech_list);
count = 0;
}
}
g_object_unref (module);
if (!count)
return NULL;
result = g_array_new (FALSE, TRUE, sizeof (CK_MECHANISM_TYPE));
for (i = 0; i < count; ++i)
g_array_append_val (result, mech_list[i]);
g_free (mech_list);
return result;
}
/**
* gck_slot_get_mechanism_info:
* @self: The slot to get mechanism info from.
* @mech_type: The mechanisms type to get info for.
*
* Get information for the specified mechanism.
*
* Returns: (transfer full): the mechanism information, or %NULL if failed; use
* gck_mechanism_info_free() when done with it
**/
GckMechanismInfo*
gck_slot_get_mechanism_info (GckSlot *self, gulong mech_type)
{
CK_SLOT_ID handle = (CK_SLOT_ID)-1;
CK_FUNCTION_LIST_PTR funcs;
GckMechanismInfo *mechinfo;
GckModule *module = NULL;
CK_MECHANISM_INFO info;
CK_RV rv;
g_return_val_if_fail (GCK_IS_SLOT (self), NULL);
g_object_get (self, "module", &module, "handle", &handle, NULL);
g_return_val_if_fail (GCK_IS_MODULE (module), NULL);
funcs = gck_module_get_functions (module);
g_return_val_if_fail (funcs, NULL);
memset (&info, 0, sizeof (info));
rv = (funcs->C_GetMechanismInfo) (handle, mech_type, &info);
g_object_unref (module);
if (rv != CKR_OK) {
g_warning ("couldn't get mechanism info: %s", gck_message_from_rv (rv));
return NULL;
}
mechinfo = g_new0 (GckMechanismInfo, 1);
mechinfo->flags = info.flags;
mechinfo->max_key_size = info.ulMaxKeySize;
mechinfo->min_key_size = info.ulMinKeySize;
return mechinfo;
}
/**
* gck_slot_has_flags:
* @self: The GckSlot object.
* @flags: The flags to check.
*
* Check if the PKCS11 slot has the given flags.
*
* Returns: Whether one or more flags exist.
*/
gboolean
gck_slot_has_flags (GckSlot *self, gulong flags)
{
CK_FUNCTION_LIST_PTR funcs;
GckModule *module = NULL;
CK_SLOT_INFO info;
CK_SLOT_ID handle;
CK_RV rv;
g_return_val_if_fail (GCK_IS_SLOT (self), FALSE);
g_object_get (self, "module", &module, "handle", &handle, NULL);
g_return_val_if_fail (GCK_IS_MODULE (module), FALSE);
funcs = gck_module_get_functions (module);
g_return_val_if_fail (funcs, FALSE);
memset (&info, 0, sizeof (info));
rv = (funcs->C_GetSlotInfo) (handle, &info);
g_object_unref (module);
if (rv != CKR_OK) {
g_warning ("couldn't get slot info: %s", gck_message_from_rv (rv));
return FALSE;
}
return (info.flags & flags) != 0;
}
/**
* gck_slot_token_has_flags:
* @self: The GckSlot object.
* @flags: The flags to check.
*
* Check if the PKCS11 token in the slot has the given flags.
*
* Returns: Whether one or more flags exist.
*/
gboolean
gck_slot_token_has_flags (GckSlot *self, gulong flags)
{
CK_FUNCTION_LIST_PTR funcs;
GckModule *module = NULL;
CK_TOKEN_INFO info;
CK_SLOT_ID handle;
CK_RV rv;
g_return_val_if_fail (GCK_IS_SLOT (self), FALSE);
g_object_get (self, "module", &module, "handle", &handle, NULL);
g_return_val_if_fail (GCK_IS_MODULE (module), FALSE);
funcs = gck_module_get_functions (module);
g_return_val_if_fail (funcs, FALSE);
memset (&info, 0, sizeof (info));
rv = (funcs->C_GetTokenInfo) (handle, &info);
g_object_unref (module);
if (rv != CKR_OK) {
g_warning ("couldn't get slot info: %s", gck_message_from_rv (rv));
return FALSE;
}
return (info.flags & flags) != 0;
}
/**
* gck_slot_enumerate_objects:
* @self: a #GckSlot to enumerate objects on
* @match: attributes that the objects must match, or empty for all objects
* @options: options for opening a session
*
* Setup an enumerator for listing matching objects on the slot.
*
* If the @match #GckAttributes is floating, it is consumed.
*
* This call will not block but will return an enumerator immediately.
*
* Returns: (transfer full): a new enumerator
**/
GckEnumerator *
gck_slot_enumerate_objects (GckSlot *self,
GckAttributes *match,
GckSessionOptions options)
{
GList *slots = NULL;
GckEnumerator *enumerator;
g_return_val_if_fail (GCK_IS_SLOT (self), NULL);
g_return_val_if_fail (match != NULL, NULL);
slots = g_list_append (slots, self);
enumerator = gck_slots_enumerate_objects (slots, match, options);
g_list_free (slots);
return enumerator;
}
/**
* gck_slots_enumerate_objects:
* @slots: (element-type Gck.Slot): a list of #GckSlot to enumerate objects on.
* @match: attributes that the objects must match, or empty for all objects
* @options: options for opening a session
*
* Setup an enumerator for listing matching objects on the slots.
*
* This call will not block but will return an enumerator immediately.
*
* Returns: (transfer full): a new enumerator
**/
GckEnumerator*
gck_slots_enumerate_objects (GList *slots,
GckAttributes *match,
GckSessionOptions options)
{
GckUriData *uri_data;
g_return_val_if_fail (match != NULL, NULL);
uri_data = gck_uri_data_new ();
uri_data->attributes = gck_attributes_ref (match);
return _gck_enumerator_new_for_slots (slots, options, uri_data);
}
/**
* gck_slot_open_session:
* @self: The slot ot open a session on.
* @options: The #GckSessionOptions to open a session with.
* @interaction: (nullable): The #GTlsInteraction to use, or %NULL.
* @cancellable: An optional cancellation object, or %NULL.
* @error: A location to return an error, or %NULL.
*
* Open a session on the slot. If the 'auto reuse' setting is set,
* then this may be a recycled session with the same flags.
*
* This call may block for an indefinite period.
*
* Returns: (transfer full): a new session or %NULL if an error occurs
**/
GckSession *
gck_slot_open_session (GckSlot *self,
GckSessionOptions options,
GTlsInteraction *interaction,
GCancellable *cancellable,
GError **error)
{
return gck_slot_open_session_full (self, options, interaction, 0, NULL, NULL, cancellable, error);
}
/**
* gck_slot_open_session_full: (skip)
* @self: The slot to open a session on.
* @options: The options to open the new session with.
* @interaction: (nullable): The #GTlsInteraction to use, or %NULL.
* @pkcs11_flags: Additional raw PKCS#11 flags.
* @app_data: Application data for notification callback.
* @notify: PKCS#11 notification callback.
* @cancellable: Optional cancellation object, or %NULL.
* @error: A location to return an error, or %NULL.
*
* Open a session on the slot. If the 'auto reuse' setting is set,
* then this may be a recycled session with the same flags.
*
* This call may block for an indefinite period.
*
* Returns: (transfer full): a new session or %NULL if an error occurs
**/
GckSession *
gck_slot_open_session_full (GckSlot *self,
GckSessionOptions options,
GTlsInteraction *interaction,
gulong pkcs11_flags,
gpointer app_data,
CK_NOTIFY notify,
GCancellable *cancellable,
GError **error)
{
return g_initable_new (GCK_TYPE_SESSION, cancellable, error,
"options", options,
"interaction", interaction,
"slot", self,
"opening-flags", pkcs11_flags,
"app-data", app_data,
NULL);
}
/**
* gck_slot_open_session_async:
* @self: The slot to open a session on.
* @options: The options to open the new session with.
* @interaction: (nullable): The #GTlsInteraction to use, or %NULL.
* @cancellable: Optional cancellation object, or %NULL.
* @callback: Called when the operation completes.
* @user_data: Data to pass to the callback.
*
* Open a session on the slot. If the 'auto reuse' setting is set,
* then this may be a recycled session with the same flags.
*
* This call will return immediately and complete asynchronously.
**/
void
gck_slot_open_session_async (GckSlot *self,
GckSessionOptions options,
GTlsInteraction *interaction,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
gck_slot_open_session_full_async (self, options, interaction, 0UL, NULL, NULL, cancellable, callback, user_data);
}
static void
on_open_session_complete (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
GTask *task = G_TASK (user_data);
GError *error = NULL;
GObject *session;
session = g_async_initable_new_finish (G_ASYNC_INITABLE (source), result, &error);
if (session != NULL)
g_task_return_pointer (task, session, g_object_unref);
else
g_task_return_error (task, g_steal_pointer (&error));
g_clear_object (&task);
}
/**
* gck_slot_open_session_full_async: (skip)
* @self: The slot to open a session on.
* @options: Options to open the new session with.
* @interaction: (nullable): The #GTlsInteraction to use, or %NULL.
* @pkcs11_flags: Additional raw PKCS#11 flags.
* @app_data: Application data for notification callback.
* @notify: PKCS#11 notification callback.
* @cancellable: (nullable): Optional cancellation object, or %NULL.
* @callback: Called when the operation completes.
* @user_data: Data to pass to the callback.
*
* Open a session on the slot. If the 'auto reuse' setting is set,
* then this may be a recycled session with the same flags.
*
* This call will return immediately and complete asynchronously.
**/
void
gck_slot_open_session_full_async (GckSlot *self,
GckSessionOptions options,
GTlsInteraction *interaction,
gulong pkcs11_flags,
gpointer app_data,
CK_NOTIFY notify,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
g_return_if_fail (GCK_IS_SLOT (self));
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_source_tag (task, gck_slot_open_session_full_async);
g_async_initable_new_async (GCK_TYPE_SESSION, G_PRIORITY_DEFAULT,
cancellable, on_open_session_complete,
g_steal_pointer (&task),
"options", options,
"interaction", interaction,
"slot", self,
"opening-flags", pkcs11_flags,
"app-data", app_data,
NULL);
g_clear_object (&task);
}
/**
* gck_slot_open_session_finish:
* @self: The slot to open a session on.
* @result: The result passed to the callback.
* @error: A location to return an error or %NULL.
*
* Get the result of an open session operation. If the 'auto reuse' setting is set,
* then this may be a recycled session with the same flags.
*
* Returns: (transfer full): the new session or %NULL if an error occurs
*/
GckSession *
gck_slot_open_session_finish (GckSlot *self, GAsyncResult *result, GError **error)
{
g_return_val_if_fail (GCK_IS_SLOT (self), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
g_return_val_if_fail (g_task_is_valid (result, self), NULL);
return g_task_propagate_pointer (G_TASK (result), error);
}
/**
* gck_slot_match:
* @self: the slot to match
* @uri: the uri to match against the slot
*
* Check whether the PKCS#11 URI matches the slot
*
* Returns: whether the URI matches or not
*/
gboolean
gck_slot_match (GckSlot *self,
GckUriData *uri)
{
GckModule *module;
GckTokenInfo *info;
gboolean match = TRUE;
g_return_val_if_fail (GCK_IS_SLOT (self), FALSE);
g_return_val_if_fail (uri != NULL, FALSE);
if (uri->any_unrecognized)
match = FALSE;
if (match && uri->module_info) {
module = gck_slot_get_module (self);
match = gck_module_match (module, uri);
g_object_unref (module);
}
if (match && uri->token_info) {
info = gck_slot_get_token_info (self);
match = _gck_token_info_match (uri->token_info, info);
gck_token_info_free (info);
}
return match;
}