/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* gck-object.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 /** * GckObject: * * Holds a handle to a PKCS11 object such as a key or certificate. Token * objects are stored on the token persistently. Others are transient and are * called session objects. */ /** * GckObjectClass: * @parent: derived from this * * The class for a [class@Object]. * * If the @attribute_types field is set by a derived class, then the a * #GckEnumerator which has been setup using [method@Enumerator.set_object_type] * with this derived type will retrieve these attributes when enumerating. In * this case the class must implement an 'attributes' property of boxed type * `GCK_TYPE_ATTRIBUTES`. */ /* * MT safe -- Nothing in GckObjectData changes between * init and finalize. All GckObjectPrivate access between init * and finalize is locked. */ enum { PROP_0, PROP_MODULE, PROP_SESSION, PROP_HANDLE }; typedef struct { GckModule *module; GckSession *session; CK_OBJECT_HANDLE handle; } GckObjectPrivate; G_DEFINE_TYPE_WITH_PRIVATE (GckObject, gck_object, G_TYPE_OBJECT); /* ---------------------------------------------------------------------------- * OBJECT */ static void gck_object_init (GckObject *self) { } static void gck_object_get_property (GObject *obj, guint prop_id, GValue *value, GParamSpec *pspec) { GckObject *self = GCK_OBJECT (obj); switch (prop_id) { case PROP_MODULE: g_value_take_object (value, gck_object_get_module (self)); break; case PROP_SESSION: g_value_take_object (value, gck_object_get_session (self)); break; case PROP_HANDLE: g_value_set_ulong (value, gck_object_get_handle (self)); break; } } static void gck_object_set_property (GObject *obj, guint prop_id, const GValue *value, GParamSpec *pspec) { GckObject *self = GCK_OBJECT (obj); GckObjectPrivate *priv = gck_object_get_instance_private (self); /* The sets to data below are only allowed during construction */ switch (prop_id) { case PROP_MODULE: g_return_if_fail (!priv->module); priv->module = g_value_dup_object (value); g_return_if_fail (priv->module); break; case PROP_SESSION: g_return_if_fail (!priv->session); priv->session = g_value_dup_object (value); g_return_if_fail (priv->session); break; case PROP_HANDLE: g_return_if_fail (!priv->handle); priv->handle = g_value_get_ulong (value); break; } } static void gck_object_finalize (GObject *obj) { GckObject *self = GCK_OBJECT (obj); GckObjectPrivate *priv = gck_object_get_instance_private (self); g_clear_object (&priv->session); g_clear_object (&priv->module); priv->handle = 0; G_OBJECT_CLASS (gck_object_parent_class)->finalize (obj); } static void gck_object_class_init (GckObjectClass *klass) { GObjectClass *gobject_class = (GObjectClass*)klass; gck_object_parent_class = g_type_class_peek_parent (klass); gobject_class->get_property = gck_object_get_property; gobject_class->set_property = gck_object_set_property; gobject_class->finalize = gck_object_finalize; /** * GckObject:module: * * The GckModule that this object belongs to. */ 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)); /** * GckObject:handle: * * The raw PKCS11 handle for this object. */ g_object_class_install_property (gobject_class, PROP_HANDLE, g_param_spec_ulong ("handle", "Object Handle", "PKCS11 Object Handle", 0, G_MAXULONG, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); /** * GckObject:session: * * The PKCS11 session to make calls on when this object needs to * perform operations on itself. * * If this is NULL then a new session is opened for each operation, * such as gck_object_get(), gck_object_set() or gck_object_destroy(). */ g_object_class_install_property (gobject_class, PROP_SESSION, g_param_spec_object ("session", "session", "PKCS11 Session to make calls on", GCK_TYPE_SESSION, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); } /* ---------------------------------------------------------------------------- * PUBLIC */ /** * gck_object_from_handle: (constructor) * @session: The session through which this object is accessed or created. * @object_handle: The raw `CK_OBJECT_HANDLE` of the object. * * Initialize a GckObject from a raw PKCS#11 handle. Normally you would use * [method@Session.create_object] or [method@Session.find_objects] to access * objects. * * Return value: (transfer full): The new object **/ GckObject * gck_object_from_handle (GckSession *session, gulong object_handle) { GckModule *module = NULL; GckObject *object; g_return_val_if_fail (GCK_IS_SESSION (session), NULL); module = gck_session_get_module (session); object = g_object_new (GCK_TYPE_OBJECT, "module", module, "handle", object_handle, "session", session, NULL); g_object_unref (module); return object; } /** * gck_objects_from_handle_array: * @session: The session for these objects * @object_handles: (array length=n_object_handles): The raw object handles. * @n_object_handles: The number of raw object handles. * * Initialize a list of GckObject from raw PKCS#11 handles. The handles argument must contain * contiguous CK_OBJECT_HANDLE handles in an array. * * Returns: (transfer full) (element-type Gck.Object): The list of #GckObject * objects. **/ GList * gck_objects_from_handle_array (GckSession *session, gulong *object_handles, gulong n_object_handles) { GList *results = NULL; CK_ULONG i; g_return_val_if_fail (GCK_IS_SESSION (session), NULL); g_return_val_if_fail (n_object_handles == 0 || object_handles != NULL, NULL); for (i = 0; i < n_object_handles; ++i) results = g_list_prepend (results, gck_object_from_handle (session, object_handles[i])); return g_list_reverse (results); } /** * gck_object_equal: * @object1: a pointer to the first #GckObject * @object2: a pointer to the second #GckObject * * Checks equality of two objects. Two GckObject objects can point to the same * underlying PKCS#11 object. * * Return value: %TRUE if object1 and object2 are equal. * %FALSE if either is not a GckObject. **/ gboolean gck_object_equal (GckObject *object1, GckObject *object2) { GckObjectPrivate *priv1 = gck_object_get_instance_private (object1); GckObjectPrivate *priv2 = gck_object_get_instance_private (object2); GckSlot *slot1, *slot2; gboolean ret; if (object1 == object2) return TRUE; if (!GCK_IS_OBJECT (object1) || !GCK_IS_OBJECT (object2)) return FALSE; slot1 = gck_session_get_slot (priv1->session); slot2 = gck_session_get_slot (priv2->session); ret = priv1->handle == priv2->handle && gck_slot_equal (slot1, slot2); g_object_unref (slot1); g_object_unref (slot2); return ret; } /** * gck_object_hash: * @object: (type Gck.Object): a pointer to a #GckObject * * Create a hash value for the GckObject. * * This function is intended for easily hashing a GckObject 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_object_hash (GckObject *object) { GckObjectPrivate *priv = gck_object_get_instance_private (object); GckSlot *slot; guint hash; g_return_val_if_fail (GCK_IS_OBJECT (object), 0); slot = gck_session_get_slot (priv->session); hash = _gck_ulong_hash (&priv->handle) ^ gck_slot_hash (slot); g_object_unref (slot); return hash; } /** * gck_object_get_handle: * @self: The object. * * Get the raw PKCS#11 handle of a GckObject. * * Return value: the raw CK_OBJECT_HANDLE object handle **/ gulong gck_object_get_handle (GckObject *self) { GckObjectPrivate *priv = gck_object_get_instance_private (self); g_return_val_if_fail (GCK_IS_OBJECT (self), (CK_OBJECT_HANDLE)-1); return priv->handle; } /** * gck_object_get_module: * @self: The object. * * Get the PKCS#11 module to which this object belongs. * * Returns: (transfer full): the module, which should be unreffed after use **/ GckModule * gck_object_get_module (GckObject *self) { GckObjectPrivate *priv = gck_object_get_instance_private (self); g_return_val_if_fail (GCK_IS_OBJECT (self), NULL); g_return_val_if_fail (GCK_IS_MODULE (priv->module), NULL); return g_object_ref (priv->module); } /** * gck_object_get_session: * @self: The object * * Get the PKCS#11 session assigned to make calls on when operating * on this object. * * This will only return a session if it was set explitly on this * object. By default an object will open and close sessions * appropriate for its calls. * * Returns: (transfer full): the assigned session, which must be unreffed after use **/ GckSession * gck_object_get_session (GckObject *self) { GckObjectPrivate *priv = gck_object_get_instance_private (self); g_return_val_if_fail (GCK_IS_OBJECT (self), NULL); g_return_val_if_fail (GCK_IS_SESSION (priv->session), NULL); return g_object_ref (priv->session); } /* -------------------------------------------------------------------------------------- * DESTROY */ typedef struct _Destroy { GckArguments base; CK_OBJECT_HANDLE object; } Destroy; static CK_RV perform_destroy (Destroy *args) { g_assert (args); return (args->base.pkcs11->C_DestroyObject) (args->base.handle, args->object); } /** * gck_object_destroy: * @self: The object to destroy. * @cancellable: Optional cancellable object, or %NULL to ignore. * @error: A location to return an error. * * Destroy a PKCS#11 object, deleting it from storage or the session. * This call may block for an indefinite period. * * Return value: Whether the call was successful or not. **/ gboolean gck_object_destroy (GckObject *self, GCancellable *cancellable, GError **error) { GckObjectPrivate *priv = gck_object_get_instance_private (self); Destroy args = { GCK_ARGUMENTS_INIT, 0 }; g_return_val_if_fail (GCK_IS_OBJECT (self), FALSE); g_return_val_if_fail (GCK_IS_SESSION (priv->session), FALSE); g_return_val_if_fail (!error || !*error, FALSE); args.object = priv->handle; return _gck_call_sync (priv->session, perform_destroy, NULL, &args, cancellable, error); } /** * gck_object_destroy_async: * @self: The object to destroy. * @cancellable: Optional cancellable object, or %NULL to ignore. * @callback: Callback which is called when operation completes. * @user_data: Data to pass to the callback. * * Destroy a PKCS#11 object, deleting it from storage or the session. * This call will return immediately and complete asynchronously. **/ void gck_object_destroy_async (GckObject *self, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GckObjectPrivate *priv = gck_object_get_instance_private (self); GckCall *call; Destroy* args; g_return_if_fail (GCK_IS_OBJECT (self)); g_return_if_fail (GCK_IS_SESSION (priv->session)); call = _gck_call_async_prep (priv->session, perform_destroy, NULL, sizeof (*args), NULL); args = _gck_call_get_arguments (call); args->object = priv->handle; _gck_call_async_ready_go (call, self, cancellable, callback, user_data); } /** * gck_object_destroy_finish: * @self: The object being destroyed. * @result: The result of the destory operation passed to the callback. * @error: A location to store an error. * * Get the status of the operation to destroy a PKCS#11 object, begun with * gck_object_destroy_async(). * * Return value: Whether the object was destroyed successfully or not. */ gboolean gck_object_destroy_finish (GckObject *self, GAsyncResult *result, GError **error) { g_return_val_if_fail (GCK_IS_OBJECT (self), FALSE); g_return_val_if_fail (G_IS_TASK (result), FALSE); return _gck_call_basic_finish (result, error); } /* -------------------------------------------------------------------------------------- * SET ATTRIBUTES */ typedef struct _SetAttributes { GckArguments base; GckAttributes *attrs; CK_OBJECT_HANDLE object; } SetAttributes; static CK_RV perform_set_attributes (SetAttributes *args) { CK_ATTRIBUTE_PTR attrs; CK_ULONG n_attrs; g_assert (args); attrs = _gck_attributes_commit_out (args->attrs, &n_attrs); return (args->base.pkcs11->C_SetAttributeValue) (args->base.handle, args->object, attrs, n_attrs); } static void free_set_attributes (SetAttributes *args) { g_assert (args); gck_attributes_unref (args->attrs); g_free (args); } /** * gck_object_set: * @self: The object to set attributes on. * @attrs: The attributes to set on the object. * @cancellable: Optional cancellable object, or %NULL to ignore. * @error: A location to return an error. * * Set PKCS#11 attributes on an object. This call may block for an indefinite period. * * Return value: Whether the call was successful or not. **/ gboolean gck_object_set (GckObject *self, GckAttributes *attrs, GCancellable *cancellable, GError **error) { GckObjectPrivate *priv = gck_object_get_instance_private (self); SetAttributes args; gboolean ret = FALSE; g_return_val_if_fail (GCK_IS_OBJECT (self), FALSE); g_return_val_if_fail (attrs != NULL, FALSE); g_return_val_if_fail (!error || !*error, FALSE); memset (&args, 0, sizeof (args)); args.attrs = attrs; args.object = priv->handle; ret = _gck_call_sync (priv->session, perform_set_attributes, NULL, &args, cancellable, error); return ret; } /** * gck_object_set_async: * @self: The object to set attributes on. * @attrs: The attributes to set on the object. * @cancellable: Optional cancellable object, or %NULL to ignore. * @callback: Callback which is called when operation completes. * @user_data: Data to pass to the callback. * * Set PKCS#11 attributes on an object. This call will return * immediately and completes asynchronously. **/ void gck_object_set_async (GckObject *self, GckAttributes *attrs, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GckObjectPrivate *priv = gck_object_get_instance_private (self); GckCall *call; SetAttributes *args; g_return_if_fail (GCK_IS_OBJECT (self)); g_return_if_fail (attrs != NULL); call = _gck_call_async_prep (priv->session, perform_set_attributes, NULL, sizeof (*args), free_set_attributes); args = _gck_call_get_arguments (call); args->attrs = gck_attributes_ref (attrs); args->object = priv->handle; _gck_call_async_ready_go (call, self, cancellable, callback, user_data); } /** * gck_object_set_finish: * @self: The object to set attributes on. * @result: The result of the destory operation passed to the callback. * @error: A location to store an error. * * Get the status of the operation to set attributes on a PKCS#11 object, * begun with gck_object_set_async(). * * Return value: Whether the attributes were successfully set on the object or not. */ gboolean gck_object_set_finish (GckObject *self, GAsyncResult *result, GError **error) { SetAttributes *args; g_return_val_if_fail (GCK_IS_OBJECT (self), FALSE); g_return_val_if_fail (G_IS_TASK (result), FALSE); g_return_val_if_fail (!error || !*error, FALSE); /* Unlock the attributes we were using */ args = _gck_call_async_result_arguments (result, SetAttributes); g_assert (args->attrs); return _gck_call_basic_finish (result, error); } /* ------------------------------------------------------------------------------------ * GET ATTRIBUTES */ typedef struct _GetAttributes { GckArguments base; CK_OBJECT_HANDLE object; GckBuilder builder; } GetAttributes; static CK_RV perform_get_attributes (GetAttributes *args) { CK_ATTRIBUTE_PTR attrs; CK_ULONG n_attrs; CK_RV rv; g_assert (args != NULL); /* Prepare all the attributes */ attrs = _gck_builder_prepare_in (&args->builder, &n_attrs); /* Get the size of each value */ rv = (args->base.pkcs11->C_GetAttributeValue) (args->base.handle, args->object, attrs, n_attrs); if (!GCK_IS_GET_ATTRIBUTE_RV_OK (rv)) return rv; /* Allocate memory for each value */ attrs = _gck_builder_commit_in (&args->builder, &n_attrs); /* Now get the actual values */ rv = (args->base.pkcs11->C_GetAttributeValue) (args->base.handle, args->object, attrs, n_attrs); if (GCK_IS_GET_ATTRIBUTE_RV_OK (rv)) rv = CKR_OK; return rv; } static void free_get_attributes (GetAttributes *args) { g_assert (args != NULL); gck_builder_clear (&args->builder); g_free (args); } /** * gck_object_get: * @self: The object to get attributes from. * @cancellable: A #GCancellable or %NULL * @error: A location to store an error. * @...: The attribute types to get. * * Get the specified attributes from the object. This call may * block for an indefinite period. * * Returns: (transfer full): the resulting PKCS#11 attributes, or %NULL if an * error occurred; the result must be unreffed when you're finished * with it **/ GckAttributes * gck_object_get (GckObject *self, GCancellable *cancellable, GError **error, ...) { GckAttributes *attrs; GArray *array; va_list va; gulong type; g_return_val_if_fail (GCK_IS_OBJECT (self), NULL); g_return_val_if_fail (!error || !*error, NULL); array = g_array_new (FALSE, TRUE, sizeof (gulong)); va_start (va, error); for (;;) { type = va_arg (va, gulong); if (type == GCK_INVALID) break; g_array_append_val (array, type); } va_end (va); attrs = gck_object_get_full (self, (gulong*)array->data, array->len, cancellable, error); g_array_free (array, TRUE); return attrs; } /** * gck_object_get_full: * @self: The object to get attributes from. * @attr_types: (array length=n_attr_types): the types of the attributes to get * @n_attr_types: the number of attr_types * @cancellable: optional cancellation object, or %NULL * @error: A location to store an error. * * Get the specified attributes from the object. This call may * block for an indefinite period. * * No extra references are added to the returned attributes pointer. * During this call you may not access the attributes in any way. * * Returns: (transfer full): a pointer to the filled in attributes if successful, * or %NULL if not **/ GckAttributes * gck_object_get_full (GckObject *self, const gulong *attr_types, guint n_attr_types, GCancellable *cancellable, GError **error) { GckObjectPrivate *priv = gck_object_get_instance_private (self); GetAttributes args; gboolean ret; guint i; g_return_val_if_fail (GCK_IS_OBJECT (self), NULL); g_return_val_if_fail (!error || !*error, NULL); memset (&args, 0, sizeof (args)); gck_builder_init (&args.builder); for (i = 0; i < n_attr_types; ++i) gck_builder_add_empty (&args.builder, attr_types[i]); args.object = priv->handle; ret = _gck_call_sync (priv->session, perform_get_attributes, NULL, &args, cancellable, error); if (ret) { return gck_builder_end (&args.builder); } else { gck_builder_clear (&args.builder); return NULL; } } /** * gck_object_get_async: * @self: The object to get attributes from. * @attr_types: (array length=n_attr_types): the types of the attributes to get * @n_attr_types: the number of attr_types * @cancellable: optional cancellation object, or %NULL * @callback: A callback which is called when the operation completes. * @user_data: Data to be passed to the callback. * * Get the specified attributes from the object. The attributes will be cleared * of their current values, and new attributes will be stored. The attributes * should not be accessed in any way except for referencing and unreferencing * them until gck_object_get_finish() is called. * * This call returns immediately and completes asynchronously. **/ void gck_object_get_async (GckObject *self, const gulong *attr_types, guint n_attr_types, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GckObjectPrivate *priv = gck_object_get_instance_private (self); GckCall *call; GetAttributes *args; guint i; g_return_if_fail (GCK_IS_OBJECT (self)); call = _gck_call_async_prep (priv->session, perform_get_attributes, NULL, sizeof (*args), free_get_attributes); args = _gck_call_get_arguments (call); gck_builder_init (&args->builder); for (i = 0; i < n_attr_types; ++i) gck_builder_add_empty (&args->builder, attr_types[i]); args->object = priv->handle; _gck_call_async_ready_go (call, self, cancellable, callback, user_data); } /** * gck_object_get_finish: * @self: The object to get attributes from. * @result: The result passed to the callback. * @error: A location to store an error. * * Get the result of a get operation and return specified attributes from * the object. * * No extra references are added to the returned attributes pointer. * * Return value: The filled in attributes structure if successful or * %NULL if not successful. **/ GckAttributes* gck_object_get_finish (GckObject *self, GAsyncResult *result, GError **error) { GetAttributes *args; g_return_val_if_fail (GCK_IS_OBJECT (self), NULL); g_return_val_if_fail (G_IS_TASK (result), NULL); g_return_val_if_fail (!error || !*error, NULL); args = _gck_call_async_result_arguments (result, GetAttributes); if (!_gck_call_basic_finish (result, error)) return NULL; return gck_builder_end (&args->builder); } /* --------------------------------------------------------------------------------- * GET ATTRIBUTE DATA */ typedef struct _GetAttributeData { GckArguments base; CK_OBJECT_HANDLE object; CK_ATTRIBUTE_TYPE type; GckAllocator allocator; guchar *result; gsize n_result; } GetAttributeData; static CK_RV perform_get_attribute_data (GetAttributeData *args) { CK_ATTRIBUTE attr; CK_RV rv; g_assert (args); g_assert (args->allocator); attr.type = args->type; attr.ulValueLen = 0; attr.pValue = 0; /* Get the size of the value */ rv = (args->base.pkcs11->C_GetAttributeValue) (args->base.handle, args->object, &attr, 1); if (rv != CKR_OK) return rv; /* Allocate memory for the value */ args->result = (args->allocator) (NULL, attr.ulValueLen + 1); g_assert (args->result); attr.pValue = args->result; /* Now get the actual value */ rv = (args->base.pkcs11->C_GetAttributeValue) (args->base.handle, args->object, &attr, 1); if (rv == CKR_OK) { args->n_result = attr.ulValueLen; args->result[args->n_result] = 0; } return rv; } static void free_get_attribute_data (GetAttributeData *args) { g_assert (args); g_free (args->result); g_free (args); } /** * gck_object_get_data: * @self: The object to get attribute data from. * @attr_type: The attribute to get data for. * @cancellable: A #GCancellable or %NULL * @n_data: The length of the resulting data. * @error: A location to store an error. * * Get the data for the specified attribute from the object. For convenience * the returned data has a null terminator. * * This call may block for an indefinite period. * * Returns: (transfer full) (array length=n_data): the resulting PKCS#11 * attribute data, or %NULL if an error occurred **/ guchar * gck_object_get_data (GckObject *self, gulong attr_type, GCancellable *cancellable, gsize *n_data, GError **error) { g_return_val_if_fail (GCK_IS_OBJECT (self), NULL); g_return_val_if_fail (n_data, NULL); g_return_val_if_fail (!error || !*error, NULL); return gck_object_get_data_full (self, attr_type, g_realloc, cancellable, n_data, error); } /** * gck_object_get_data_full: (skip) * @self: The object to get attribute data from. * @attr_type: The attribute to get data for. * @allocator: An allocator with which to allocate memory for the data, or %NULL for default. * @cancellable: Optional cancellation object, or %NULL. * @n_data: The length of the resulting data. * @error: A location to store an error. * * Get the data for the specified attribute from the object. For convenience * the returned data has an extra null terminator, not included in the returned length. * * This call may block for an indefinite period. * * Returns: (transfer full) (array length=n_data): The resulting PKCS#11 * attribute data, or %NULL if an error occurred. **/ guchar * gck_object_get_data_full (GckObject *self, gulong attr_type, GckAllocator allocator, GCancellable *cancellable, gsize *n_data, GError **error) { GckObjectPrivate *priv = gck_object_get_instance_private (self); GetAttributeData args; gboolean ret; g_return_val_if_fail (GCK_IS_OBJECT (self), NULL); g_return_val_if_fail (n_data, NULL); g_return_val_if_fail (!error || !*error, NULL); if (!allocator) allocator = g_realloc; memset (&args, 0, sizeof (args)); args.allocator = allocator; args.object = priv->handle; args.type = attr_type; ret = _gck_call_sync (priv->session, perform_get_attribute_data, NULL, &args, cancellable, error); /* Free any value if failed */ if (!ret) { if (args.result) (allocator) (args.result, 0); return NULL; } *n_data = args.n_result; return args.result; } /** * gck_object_get_data_async: * @self: The object to get attribute data from. * @attr_type: The attribute to get data for. * @allocator: (skip): An allocator with which to allocate memory for the data, or %NULL for default. * @cancellable: Optional cancellation object, or %NULL. * @callback: Called when the operation completes. * @user_data: Data to be passed to the callback. * * Get the data for the specified attribute from the object. * * This call will return immediately and complete asynchronously. **/ void gck_object_get_data_async (GckObject *self, gulong attr_type, GckAllocator allocator, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GckObjectPrivate *priv = gck_object_get_instance_private (self); GckCall *call; GetAttributeData *args; g_return_if_fail (GCK_IS_OBJECT (self)); if (!allocator) allocator = g_realloc; call = _gck_call_async_prep (priv->session, perform_get_attribute_data, NULL, sizeof (*args), free_get_attribute_data); args = _gck_call_get_arguments (call); args->allocator = allocator; args->object = priv->handle; args->type = attr_type; _gck_call_async_ready_go (call, self, cancellable, callback, user_data); } /** * gck_object_get_data_finish: * @self: The object to get an attribute from. * @result: The result passed to the callback. * @n_data: The length of the resulting data. * @error: A location to store an error. * * Get the result of an operation to get attribute data from * an object. For convenience the returned data has an extra null terminator, * not included in the returned length. * * Returns: (transfer full) (array length=n_data): The PKCS#11 attribute data * or %NULL if an error occurred. **/ guchar * gck_object_get_data_finish (GckObject *self, GAsyncResult *result, gsize *n_data, GError **error) { GetAttributeData *args; guchar *data; g_return_val_if_fail (GCK_IS_OBJECT (self), NULL); g_return_val_if_fail (G_IS_TASK (result), NULL); g_return_val_if_fail (n_data, NULL); g_return_val_if_fail (!error || !*error, NULL); if (!_gck_call_basic_finish (result, error)) return NULL; args = _gck_call_async_result_arguments (result, GetAttributeData); *n_data = args->n_result; data = args->result; args->result = NULL; return data; } /* --------------------------------------------------------------------------------------- * SET TEMPLATE */ typedef struct _set_template_args { GckArguments base; CK_OBJECT_HANDLE object; CK_ATTRIBUTE_TYPE type; GckAttributes *attrs; } set_template_args; static CK_RV perform_set_template (set_template_args *args) { CK_ATTRIBUTE attr; CK_ULONG n_attrs; g_assert (args); attr.type = args->type; attr.pValue = _gck_attributes_commit_out (args->attrs, &n_attrs); attr.ulValueLen = n_attrs * sizeof (CK_ATTRIBUTE); return (args->base.pkcs11->C_SetAttributeValue) (args->base.handle, args->object, &attr, 1); } static void free_set_template (set_template_args *args) { g_assert (args); gck_attributes_unref (args->attrs); g_free (args); } /** * gck_object_set_template: * @self: The object to set an attribute template on. * @attr_type: The attribute template type. * @attrs: The attribute template. * @cancellable: Optional cancellation object, or %NULL. * @error: A location to store an error. * * Set an attribute template on the object. The attr_type must be for * an attribute which contains a template. * * If the @attrs #GckAttributes is floating, it is consumed. * * This call may block for an indefinite period. * * Return value: %TRUE if the operation succeeded. **/ gboolean gck_object_set_template (GckObject *self, gulong attr_type, GckAttributes *attrs, GCancellable *cancellable, GError **error) { GckObjectPrivate *priv = gck_object_get_instance_private (self); set_template_args args; gboolean ret = FALSE; g_return_val_if_fail (GCK_IS_OBJECT (self), FALSE); g_return_val_if_fail (attrs, FALSE); g_return_val_if_fail (!error || !*error, FALSE); memset (&args, 0, sizeof (args)); args.attrs = attrs; args.type = attr_type; args.object = priv->handle; ret = _gck_call_sync (priv->session, perform_set_template, NULL, &args, cancellable, error); return ret; } /** * gck_object_set_template_async: * @self: The object to set an attribute template on. * @attr_type: The attribute template type. * @attrs: The attribute template. * @cancellable: Optional cancellation object, or %NULL. * @callback: Called when the operation completes. * @user_data: Data to be passed to the callback. * * Set an attribute template on the object. The attr_type must be for * an attribute which contains a template. * * If the @attrs #GckAttributes is floating, it is consumed. * * This call will return immediately and complete asynchronously. **/ void gck_object_set_template_async (GckObject *self, gulong attr_type, GckAttributes *attrs, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GckObjectPrivate *priv = gck_object_get_instance_private (self); GckCall *call; set_template_args *args; g_return_if_fail (GCK_IS_OBJECT (self)); g_return_if_fail (attrs); call = _gck_call_async_prep (priv->session, perform_set_template, NULL, sizeof (*args), free_set_template); args = _gck_call_get_arguments (call); args->attrs = gck_attributes_ref (attrs); args->type = attr_type; args->object = priv->handle; _gck_call_async_ready_go (call, self, cancellable, callback, user_data); } /** * gck_object_set_template_finish: * @self: The object to set an attribute template on. * @result: The result passed to the callback. * @error: A location to store an error. * * Get the result of an operation to set attribute template on * an object. * * Return value: %TRUE if the operation succeeded. **/ gboolean gck_object_set_template_finish (GckObject *self, GAsyncResult *result, GError **error) { set_template_args *args; g_return_val_if_fail (GCK_IS_OBJECT (self), FALSE); g_return_val_if_fail (G_IS_TASK (result), FALSE); g_return_val_if_fail (!error || !*error, FALSE); /* Unlock the attributes we were using */ args = _gck_call_async_result_arguments (result, set_template_args); g_assert (args->attrs); return _gck_call_basic_finish (result, error); } /* --------------------------------------------------------------------------------------- * GET TEMPLATE */ typedef struct _get_template_args { GckArguments base; CK_OBJECT_HANDLE object; CK_ATTRIBUTE_TYPE type; GckBuilder builder; } get_template_args; static CK_RV perform_get_template (get_template_args *args) { CK_ATTRIBUTE attr; CK_ULONG n_attrs, i; CK_RV rv; g_assert (args); gck_builder_init (&args->builder); attr.type = args->type; attr.ulValueLen = 0; attr.pValue = 0; /* Get the length of the entire template */ rv = (args->base.pkcs11->C_GetAttributeValue) (args->base.handle, args->object, &attr, 1); if (rv != CKR_OK) return rv; /* Number of attributes, rounded down */ n_attrs = (attr.ulValueLen / sizeof (CK_ATTRIBUTE)); for (i = 0; i < n_attrs; ++i) gck_builder_add_empty (&args->builder, 0); /* Prepare all the attributes */ attr.pValue = _gck_builder_prepare_in (&args->builder, &n_attrs); /* Get the size of each value */ rv = (args->base.pkcs11->C_GetAttributeValue) (args->base.handle, args->object, &attr, 1); if (rv != CKR_OK) return rv; /* Allocate memory for each value */ attr.pValue = _gck_builder_commit_in (&args->builder, &n_attrs); /* Now get the actual values */ return (args->base.pkcs11->C_GetAttributeValue) (args->base.handle, args->object, &attr, 1); } static void free_get_template (get_template_args *args) { g_assert (args != NULL); gck_builder_clear (&args->builder); g_free (args); } /** * gck_object_get_template: * @self: The object to get an attribute template from. * @attr_type: The template attribute type. * @cancellable: Optional cancellation object, or %NULL. * @error: A location to store an error. * * Get an attribute template from the object. The attr_type must be for * an attribute which returns a template. * * This call may block for an indefinite period. * * Returns: (transfer full): the resulting PKCS#11 attribute template, or %NULL * if an error occurred **/ GckAttributes * gck_object_get_template (GckObject *self, gulong attr_type, GCancellable *cancellable, GError **error) { GckObjectPrivate *priv = gck_object_get_instance_private (self); get_template_args args; gboolean ret; g_return_val_if_fail (GCK_IS_OBJECT (self), NULL); g_return_val_if_fail (!error || !*error, NULL); memset (&args, 0, sizeof (args)); args.object = priv->handle; args.type = attr_type; ret = _gck_call_sync (priv->session, perform_get_template, NULL, &args, cancellable, error); /* Free any value if failed */ if (!ret) { gck_builder_clear (&args.builder); return NULL; } return gck_builder_end (&args.builder); } /** * gck_object_get_template_async: * @self: The object to get an attribute template from. * @attr_type: The template attribute type. * @cancellable: (nullable): Optional cancellation object, or %NULL. * @callback: Called when the operation completes. * @user_data: Data to be passed to the callback. * * Get an attribute template from the object. The @attr_type must be for * an attribute which returns a template. * * This call will return immediately and complete asynchronously. **/ void gck_object_get_template_async (GckObject *self, gulong attr_type, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GckObjectPrivate *priv = gck_object_get_instance_private (self); GckCall *call; get_template_args *args; g_return_if_fail (GCK_IS_OBJECT (self)); call = _gck_call_async_prep (priv->session, perform_get_template, NULL, sizeof (*args), free_get_template); args = _gck_call_get_arguments (call); args->object = priv->handle; args->type = attr_type; _gck_call_async_ready_go (call, self, cancellable, callback, user_data); } /** * gck_object_get_template_finish: * @self: The object to get an attribute from. * @result: The result passed to the callback. * @error: A location to store an error. * * Get the result of an operation to get attribute template from * an object. * * Returns: (transfer full): the resulting PKCS#11 attribute template, or %NULL * if an error occurred **/ GckAttributes * gck_object_get_template_finish (GckObject *self, GAsyncResult *result, GError **error) { get_template_args *args; g_return_val_if_fail (GCK_IS_OBJECT (self), NULL); g_return_val_if_fail (G_IS_TASK (result), NULL); g_return_val_if_fail (!error || !*error, NULL); if (!_gck_call_basic_finish (result, error)) return NULL; args = _gck_call_async_result_arguments (result, get_template_args); return gck_builder_end (&args->builder); }